代码之家  ›  专栏  ›  技术社区  ›  Michiel Borkent

调用重新定义的函数时f和clojure的区别

  •  12
  • Michiel Borkent  · 技术社区  · 15 年前

    在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
    

    在克洛杰里:

    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
    

    注意,在clojure中,最新版本的f在最后一行被调用。然而,在f中,仍然调用f的旧版本。为什么会这样,怎么会这样?

    3 回复  |  直到 13 年前
        1
  •  8
  •   Community CDub    8 年前

    AS 盖博 said,f交互使用 遮蔽 输入已存在名称的函数时的值(有关阴影的详细信息,请参见 this SO question )这意味着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 
    

    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
    

    这应该使区别非常清楚。

    顺便说一下,clojure方法有一个可能的问题(至少对于f_之类的语言)。您可以声明某种类型的函数,使用它,然后,下一个命令可以更改函数的类型。如果f使用clojure方法,下面的示例应该如何工作?

    > let f a b = a + b;;
    > let g x = f x x;;
    > let f () = printf "f!";;
    > g 0;;
    

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

        2
  •  12
  •   Gabe Timothy Khouri    15 年前

    在克洛朱尔 f 符号捕获名称 f ,而在 f 符号捕获的值 f . 所以每次你打电话给Clojure g 它抬起头来 f 当你每次打电话给 G 使用的值 f 曾经当 G 函数最初是创建的。

        3
  •  5
  •   kvb    15 年前

    加布和托马斯已经很好地涵盖了基本知识。注意,如果希望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