调用重定义函数时F#和Clojure的差异

调用重定义函数时F#和Clojure的差异,f#,comparison,clojure,F#,Comparison,Clojure,在F#中: 在Clojure中: > let f x = x + 2;; val f : int -> int > let g x = f x;; val g : int -> int > g 10;; val it : int = 12 > let f x = x + 3;; val f : int -> int > g 10;; val it : int = 12 注意,在Clojure中,在最后一行调用了f的最新版本。然而,在F

在F#中:

在Clojure中:

> let f x = x + 2;;

val f : int -> int

> let g x = f x;;

val g : int -> int

> g 10;;
val it : int = 12
> let f x = x + 3;;

val f : int -> int

> g 10;;
val it : int = 12

注意,在Clojure中,在最后一行调用了f的最新版本。然而,在F#中,仍然称为F的旧版本。这是为什么?它是如何工作的?

在Clojure中,
f
符号捕获名称
f
,而在f中,
f
符号捕获
f
的值。因此,在Clojure中,每次调用
g
时,它都会查找
f
,以找出当时名称所指的内容,而在f#中,每次调用
g
时,都会使用
f
最初创建
g
函数时的值,F#interactive在输入一个名称已经存在的函数时使用值的阴影(有关阴影的更多信息,请参见示例)。这意味着当您运行代码时,F#编译器会看到类似的情况:

1:1 user=> (defn f [x] (+ x 2))
#'user/f
1:2 user=> (defn g [x] (f x))
#'user/g
1:3 user=> (g 10)
12
1:4 user=> (defn f [x] (+ x 3))
#'user/f
1:5 user=> (g 10)
13
F#使用了一些损坏的名称(如@),您无法直接使用它们来区分值的版本。另一方面,Clojure的行为可以最好地理解为一个功能大词典。使用伪语法,如下所示:

> let f@1 x = x + 2;; 
> let g@1 x = f@1 x;; 
> g@1 10;; 
val it : int = 12
> let f@2 x = x + 3;; 
> g@1 10;; 
val it : int = 12 
这应该使区别非常清楚

作为补充说明,Clojure方法可能存在一个问题(至少对于像F#这样的语言)。您可以声明某种类型的函数,使用它,然后,下一个命令可以更改函数的类型。如果F#使用Clojure方法,下面的示例应该如何工作

> symbols[f] = fun x -> x + 2;; 
> symbols[g] = fun x -> symbols[f] x;; 
> symbols[g] 10;; 
val it : int = 12
> symbols[f] = fun x -> x + 3;; 
> symbols[g] 10;; 
val it : int = 13

函数
g
使用
f
,就好像它有两个
int
类型的参数一样,但是第三行改变了函数的类型。这使得Clojure方法对于类型检查语言来说有点棘手。

Gabe和Tomas已经很好地介绍了基础知识。请注意,如果希望F#像Clojure那样工作,可以使用可变绑定并重新分配
F

> let f a b = a + b;;
> let g x = f x x;;
> let f () = printf "f!";;
> g 0;;
让可变f=funx->x+2
设gx=fx
g 10;;//12
f x+3//注意,分配新值,不创建新绑定
g 10//13

您的意思是阴影化是指较低范围内的变量与较高范围内的变量同名“阴影”吗?在F#interactive中,我们应该将连续的let语句作为嵌套作用域来读取吗?那就可以解释了!在Clojure案例中,这不是一个范围问题,而是真正改变了var f的根绑定(vars是可变的)。@Michiel-是的,这是完全正确的。使用F#的非轻量级语法,您的示例将是
let F=。。。in(让g=…in(g10;让f=…in g10))
,其中新作用域的创建更为明显。
let mutable f = fun x -> x + 2
let g x = f x

g 10;; // 12

f <- fun x -> x + 3 // note, assign new value, don't create new binding

g 10;; //13