gpt4 book ai didi

compiler-errors - OCaml 用高阶函数标记参数顺序

转载 作者:行者123 更新时间:2023-12-02 10:43:45 25 4
gpt4 key购买 nike

this section Real World OCaml,它基本上说:

let apply_to_tuple f (first, second) = f ~first ~second
let apply_to_tuple_2 f (first, second) = f ~second ~first
let divide ~first ~second = first / second

这允许 apply_to_tuple divide (3, 4) 工作,但不是 apply_to_tuple_2 divide (3, 4)。后者抛出:

Error: This expression has type first:int -> second:int -> int
but an expression was expected of type second:'a -> first:'b -> 'c

我想知道为什么会这样。似乎这里没有任何歧义,编译器可以正确地推断出一切?

最佳答案

虽然看起来是这样

first:int -> second:int -> int

second:int -> first:int -> int

是一样的,其实不是因为副作用。

考虑以下两个函数:

let foo ~a =
print_endline "a";
fun ~b ->
print_endline "b"

let bar ~b =
print_endline "b";
fun ~a ->
print_endline "a"

foo 的类型为 a:'a -> b:'a -> unitbar 的类型为 b:' a -> a:'a -> 单位foo 在接受第一个参数后打印 "a",在接受第二个参数后打印 "b"bar 在收到第一个参数后打印 "b",在收到第二个参数后打印 "a"

OCaml 确保这些函数中的副作用恰好在提供该副作用之前的所有参数时发生。

所以 foo 将打印 "a" 一旦它被赋予一个标记为 ~a 的参数:

# let foo2 = foo ~a:();;
a
val foo2 : b:'_a -> unit = <fun>

一旦提供了 ~a~b,它将打印 "b":

# foo2 ~b:();;
b
- : unit = ()

bar 在给定标记为 ~a 的参数时不会打印任何内容:

# let bar2 = bar ~a:();;
val bar2 : b:'a -> unit = <fun>

因为两个打印语句都在 ~b 参数之下。一旦它也被赋予了 ~b 参数——所以 ~a~b 都被提供了——它将打印两个 “b”“a”:

# bar2 ~b:();;
b
a
- : unit = ()

像这样保持副作用的正确顺序需要 OCaml 将第一个标记参数与第二个标记参数区别对待:

  • 当 OCaml 看到第一个标记参数的应用时,它必须应用该函数并在其下执行任何副作用。

  • 当 OCaml 发现第二个参数的应用时,它必须构建一个等待第一个参数的新函数,当它接收到时,它将使用第一个和第二个参数应用原始函数。

这意味着类型中参数的顺序很重要,您不能简单地使用 second:int -> first:int -> int 值,其中 first:int -> second:int -> int 预期值。

OCaml 可能会尝试在运行时将第一个参数的应用程序与其他应用程序区分开来,因此不需要在类型系统中跟踪这一点,但这会使标记函数的效率远低于常规函数.

关于compiler-errors - OCaml 用高阶函数标记参数顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33509719/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com