【问题标题】:OCaml evaluation of expression, order?OCaml 评估表达式,顺序?
【发布时间】:2018-07-04 21:54:44
【问题描述】:

add 是 OCaml 内置的函数。

经验:

# add 5 1;;
- : int = 6

我的问题:add 3 (add 5 3) 的评估顺序是什么?

# add 3 (add 5 3);;
- : int = 11

(add 5 3) 是否首先评估为 8,然后add 3 (8) 评估为 11?还是先将add 3 求值成函数,然后将(add 5 3) 作为函数(add 3) 的参数?

谢谢。

【问题讨论】:

    标签: expression ocaml evaluation


    【解决方案1】:

    不管怎样,OCaml 没有内置名为 add 的函数。 (即,Pervasives 模块中没有这样的符号。)

    $ ocaml
            OCaml version 4.06.0
    
    # add;;
    Error: Unbound value add
    

    OCaml 中函数及其参数的求值顺序未指定。所以没有保证顺序。

    这在Section 7.7.1 of the OCaml manual中有记录。

    如果您希望按特定顺序进行评估,您可以使用let 来评估每个子表达式:

    # let add a b = a + b;;
    val add : int -> int -> int = <fun>
    # let temp = add 5 3 in
      add 3 temp;;
    - : int = 11
    # let tempf = add 3 in
      tempf (add 5 3);;
    - : int = 11
    

    【讨论】:

      【解决方案2】:

      为了完成 Jeffrey 的回答,这里是 add 的一个版本,它可以让您知道它何时执行:

      # let add a b =
          Printf.printf "Adding %d and %d...\n" a b;
          a + b;;
      
      val add : int -> int -> int = <fun>
      

      让我们看看它的实际效果。

      # add (add 1 2) (add 5 8);;
      
      Adding 5 and 8...
      Adding 1 and 2...
      Adding 3 and 13...
      
      - : int = 16
      

      所以在这里,首先评估第二个add,但你不能真正指望它,因为它没有指定。

      这是使用本地 let 强制排序的相同示例:

      # let x = add 1 2 in
        add x (add 5 8);;
      
      Adding 1 and 2...
      Adding 5 and 8...
      Adding 3 and 13...
      
      - : int = 16
      

      现在使用部分应用程序。

      # let add_3 = add 3 in
        add_3 (add 5 8);;
      
      Adding 5 and 8...
      Adding 3 and 13...
      
      - : int = 16
      

      当然,对于(纯)函数式编程,执行顺序无关紧要,因为一切都是不可变的。但是 OCaml 并不是纯粹的函数式,所以这些小技巧很值得了解。 :)

      【讨论】:

        【解决方案3】:

        OCaml 中参数的求值顺序未指定,这意味着它可以从一个编译器更改为另一个。

        让我们创建一个分两个阶段评估的函数:

        let mul a =
          Printf.printf "got a: %i\n%!" a;
          fun b ->
            Printf.printf "got b: %i\n%!" b;
            a * b
        

        使用utop(或ocaml)运行它会显示从右到左的评估:

        # mul (mul 2 3) (mul 5 7);;
        got a: 5
        got b: 7
        got a: 2
        got b: 3
        got a: 6
        got b: 35
        - : int = 210
        

        可以引入let-in 来强制求值顺序,从而产生不同的 printfs 序列:

        # let mul6 = mul (mul 2 3) in mul6 (mul 5 7);;
        got a: 2
        got b: 3
        got a: 6
        got a: 5
        got b: 7
        got b: 35
        - : int = 210
        

        【讨论】:

        • 请注意,在当前的编译器中,这恰好像喂栈机器一样工作。所有参数都以相反的顺序评估并放入堆栈。然后,当参数再次从堆栈中拉回时,该函数被获取并应用于参数。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-09
        • 2012-02-25
        • 1970-01-01
        • 2018-06-06
        • 1970-01-01
        相关资源
        最近更新 更多