真正的陈述性语言?

时间:2010-06-07 15:26:11

标签: programming-languages functional-programming domain-driven-design lazy-evaluation

有谁知道真正的声明性语言?我正在寻找的行为类似于Excel所做的事情,我可以在其中定义变量和公式,并在输入发生变化时更改公式的结果(没有自己再次设置答案)

我正在寻找的行为最好用这个伪代码显示:

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

Z = X + Y  // declare a formula that uses these two variables

X = 50     // change one of the input variables

?Z         // asking for Z should now give 70 (50 + 20)

我已经尝试过很多语言,如F#,python,matlab等,但每次尝试这个时,他们都会提出30而不是70.从命令的角度来看,这是正确的,但我是如果你知道我的意思,寻找一个更加充满期待的行为。

这只是一个非常简单的计算。当事情变得更加困难时,它应该自动处理递归和记忆等事情。

下面的代码显然可以在C#中运行,但它只是为了这份工作的代码,我正在寻找更多的东西,而没有那些'技术噪音'

class BlaBla{
    public int X {get;set;}  // this used to be even worse before 3.0
    public int Y {get;set;}
    public int Z {get{return X + Y;}}
}

static void main(){
   BlaBla bla = new BlaBla();
   bla.X = 10;
   bla.Y = 20;
   // can't define anything here
   bla.X = 50; // bit pointless here but I'll do it anyway. 
   Console.Writeline(bla.Z);// 70, hurray!
}

这看起来像是如此多的代码,花括号和分号,什么也没有添加。

是否有语言/应用程序(Exel除外)这样做?也许我在上面提到的语言中没有做到这一点,或者我完全错过了这样做的应用程序。

我制作了一个语言/应用程序原型(以及其他一些东西)并且正在考虑将其产品化。我简直不敢相信它还没有。不想浪费我的时间。

19 个答案:

答案 0 :(得分:17)

任何Constraint Programming系统都会为您做到这一点。 具有相关语言的CP系统的示例是ECLiPSe,SICSTUS Prolog / CP包,Comet,MiniZinc,......

答案 1 :(得分:15)

看起来你只想让Z存储一个函数而不是一个值。在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());

因此,? - 前缀语法的等价物是() - 后缀,但是它是相同的。 lambda是你术语中的“公式”。

在幕后,C#编译器几乎完全构建了您在C#概念示例中提供的内容:它将X放入编译器生成的类中的字段中,并在代码块中分配该类的实例进入。所以恭喜你,你重新发现了lambdas! :)

答案 2 :(得分:9)

在Mathematica中,您可以这样做:

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 *)

运算符:=(SetDelayed)与=(Set)不同。前者将未评估的表达式绑定到变量,后者绑定评估的表达式

答案 3 :(得分:5)

希望有两个X定义是固有的命令式。在真正的声明性语言中,您可以在单个范围内对变量进行单一定义。您希望从Excel中执行的操作对应于编辑程序。

答案 4 :(得分:3)

你见过Resolver One吗?它就像Excel背后有一种真正的编程语言。

答案 5 :(得分:3)

这是Daniel在Python中的例子,因为我注意到你说你在Python中尝试过它。

x = 10
y = 10

z = lambda: x + y

# Output: 20
print z()

x = 20

# Output: 30
print z()

答案 6 :(得分:2)

您可以看到的两件事是cells lisp库和Modelica动态建模语言,它们都具有关系/方程功能。

答案 7 :(得分:2)

react是一个OCaml frp库。与具有闭包的天真模拟相反,它仅在需要时重新计算值

        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

答案 8 :(得分:2)

如果您使用bind代替=来支持Z

,JavaFX会为您执行此操作

答案 9 :(得分:2)

有一种具有这种行为的Lisp库:

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

答案 10 :(得分:1)

你可以在Tcl中做一些。在tcl中,您可以在变量上设置跟踪,以便无论何时访问它,都可以调用过程。该程序可以动态重新计算该值。

以下是一个可以或多或少地提出要求的工作示例:

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

答案 11 :(得分:0)

Groovy和闭包的魔力。

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)

也可以为函数添加自动记忆,但它比一两行更复杂。 http://blog.dinkla.net/?p=10

答案 12 :(得分:0)

在F#中,有点啰嗦:

let x = ref 10
let y = ref 20

let z () = !x + !y

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

答案 13 :(得分:0)

你可以在Ruby中模仿它:

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

完全与你想要的相同,但非常接近。

答案 14 :(得分:0)

您可能会发现this video(来自Commercial Users of Functional Programming网站)有趣且值得一看。如果你有漂亮的技术恐惧症用户,这可能是一个很好的方法。

答案 15 :(得分:0)

不确定metapost(1)对您的应用程序有多好,但它是声明性的。

答案 16 :(得分:0)

Lua 5.1.4版权所有(C)1994-2008 Lua.org,PUC-Rio

  

x = 10
  y = 20
  z = function()返回x + y;结束
  x = 50
  = z()
  70

答案 17 :(得分:-1)

这不是您要找的东西,但根据定义,硬件描述语言是“声明性的”。

答案 18 :(得分:-1)

这个F#代码应该可以解决问题。您可以使用延迟评估(System.Lazy对象)来确保在实际需要时评估表达式,而不是更快。

let mutable x = 10;
let y = 20;

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

printf "%d" z.Value