Truly declarative language?

假如想象 提交于 2019-12-02 22:21:16

Any Constraint Programming system will do that for you. Examples of CP systems that have an associated language are ECLiPSe, SICSTUS Prolog / CP package, Comet, MiniZinc, ...

It looks like you just want to make Z store a function instead of a value. In C#:

var X = 10;    // define and assign two variables
var Y = 20;

Func<int> Z = () => X + Y;  // declare a formula that uses these two variables

Console.WriteLine(Z());

X = 50;     // change one of the input variables

Console.WriteLine(Z());

So the equivalent of your ?-prefix syntax is a ()-suffix, but otherwise it's identical. A lambda is a "formula" in your terminology.

Behind the scenes, the C# compiler builds almost exactly what you presented in your C# conceptual example: it makes X into a field in a compiler-generated class, and allocates an instance of that class when the code block is entered. So congratulations, you have re-discovered lambdas! :)

In Mathematica, you can do this:

x = 10;     (* # assign 30 to the variable x *)
y = 20;     (* # assign 20 to the variable y *)
z := x + y; (* # assign the expression x+y to the variable z *)
Print[z];
(* # prints 30 *)
x = 50;
Print[z];
(* # prints 70 *)

The operator := (SetDelayed) is different from = (Set). The former binds an unevaluated expression to a variable, the latter binds an evaluated expression.

Wanting to have two definitions of X is inherently imperative. In a truly declarative language you have a single definition of a variable in a single scope. The behavior you want from Excel corresponds to editing the program.

Have you seen Resolver One? It's like Excel with a real programming language behind it.

Wayne Werner

Here is Daniel's example in Python, since I noticed you said you tried it in Python.

x = 10
y = 10

z = lambda: x + y

# Output: 20
print z()

x = 20

# Output: 30
print z()

Two things you can look at are the cells lisp library, and the Modelica dynamic modelling language, both of which have relation/equation capabilities.

There is a Lisp library with this sort of behaviour:

http://common-lisp.net/project/cells/

JavaFX will do that for you if you use bind instead of = for Z

react is an OCaml frp library. Contrary to naive emulations with closures it will recalculate values only when needed

        Objective Caml version 3.11.2

# #use "topfind";;
# #require "react";;
# open React;;
# let (x,setx) = S.create 10;;
val x : int React.signal = <abstr>
val setx : int -> unit = <fun>
# let (y,sety) = S.create 20;;
val y : int React.signal = <abstr>
val sety : int -> unit = <fun>
# let z = S.Int.(+) x y;;
val z : int React.signal = <abstr>
# S.value z;;
- : int = 30
# setx 50;;
- : unit = ()
# S.value z;;
- : int = 70

You can do this in Tcl, somewhat. In tcl you can set a trace on a variable such that whenever it is accessed a procedure can be invoked. That procedure can recalculate the value on the fly.

Following is a working example that does more or less what you ask:

proc main {} {
    set x 10
    set y 20
    define z {$x + $y}

    puts "z (x=$x): $z"
    set x 50
    puts "z (x=$x): $z"
}


proc define {name formula} {
    global cache
    set cache($name) $formula
    uplevel trace add variable $name read compute
}

proc compute {name _ op} {
    global cache
    upvar $name var
    if {[info exists cache($name)]} {
        set expr $cache($name)
    } else {
        set expr $var
    }
    set var [uplevel expr $expr]
}

main

Groovy and the magic of closures.

def (x, y) = [ 10, 20 ]

def z = { x + y }

assert 30 == z()

x = 50

assert 70 == z()

def f = { n -> n + 1 }  // define another closure

def g = { x + f(x) }    // ref that closure in another

assert 101 == g()       // x=50, x + (x + 1)

f = { n -> n + 5 }     // redefine f()

assert 105 == g()      // x=50, x + (x + 5)

It's possible to add automagic memoization to functions too but it's a lot more complex than just one or two lines. http://blog.dinkla.net/?p=10

In F#, a little verbosily:

let x = ref 10
let y = ref 20

let z () = !x + !y

z();;
y <- 40
z();;

You can mimic it in Ruby:

x = 10
y = 20
z = lambda { x + y }
z.call    # => 30
z = 50
z.call    # => 70

Not quite the same as what you want, but pretty close.

You might find this video (from the Commercial Users of Functional Programming website) interesting and worthwhile viewing. If you've got pretty technophobic users this may be a good approach for you.

not sure how well metapost (1) would work for your application, but it is declarative.

Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio

x = 10
y = 20
z = function() return x + y; end
x = 50
= z()
70

It's not what you're looking for, but Hardware Description Languages are, by definition, "declarative".

This F# code should do the trick. You can use lazy evaluation (System.Lazy object) to ensure your expression will be evaluated when actually needed, not sooner.

let mutable x = 10;
let y = 20;

let z = lazy (x + y);
x <- 30;

printf "%d" z.Value
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!