Mic*_*ent 12 comparison f# clojure
在F#中:
> 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
Run Code Online (Sandbox Code Playgroud)
在Clojure中:
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
Run Code Online (Sandbox Code Playgroud)
请注意,在Clojure中,最后一个版本的f在最后一行中被调用.在F#中,仍然会调用旧版本的f.为什么会这样,这是如何工作的?
Gab*_*abe 12
在Clojure中,f
符号捕获名称f
,而在F#中,f
符号捕获值f
.所以在Clojure中,每次调用g
它时f
都要查找当时名称所指的内容,而在F#中,每次调用都会g
使用最初创建函数f
时的值g
.
正如gabe所说,当您输入名称已存在的函数时,F#interactive使用值的阴影(有关阴影的更多信息,请参阅此SO问题).这意味着当您运行代码时,F#编译器会看到类似这样的内容:
> 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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这应该使区分非常清楚.
作为旁注,Clojure方法存在一个可能的问题(至少对于像F#这样的语言).您可以声明某种类型的函数,使用它然后,下一个命令可以更改函数的类型.如果F#使用Clojure方法,下面的例子应如何工作?
> let f a b = a + b;;
> let g x = f x x;;
> let f () = printf "f!";;
> g 0;;
Run Code Online (Sandbox Code Playgroud)
该函数g
使用f
好像它有两个类型的参数int
,但是thrid行改变了函数的类型.这使得Clojure方法对于类型检查语言来说有点棘手.
Gabe和Tomas很好地介绍了基础知识.请注意,如果您希望F#的行为与Clojure相同,则可以使用可变绑定并重新分配f
:
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
Run Code Online (Sandbox Code Playgroud)