从Lisp来到OCaml,我发现自己对函数何时返回以及何时不返回感到非常困惑。我想念我的魔术报价!值得庆幸的是,大多数时候,OCaml似乎能够自动地知道我什么时候需要评估功能,何时不需要。但是,我经常发现自己试图在let表达式中分配函数的返回值,如下所示。
let start = Sys.time in
(*
* do something here
*)
;
let ending = Sys.time in
Printf.printf "did something in %f seconds\n" (ending -. start)
然后ocamlc抱怨
Error: This Expression has type unit -> float
but an expression was expected of type float
告诉我开始和结束都绑定到Sys.time
,而不是Sys.time
的返回值。
这种行为我是不是想尝试不是OCamly?我想以另一种方式做事吗?我只是遗漏了一些完全明显的东西吗?
答案 0 :(得分:10)
将函数应用于参数时,将评估函数。即当您执行f
时,f
永远不会被评估。当您执行f x
时,f
始终会得到评估。它没什么神奇之处。
正如您正确指出的那样,Sys.time
是一个函数(类型为unit -> float
),而let start = Sys.time
只是将该函数指定给start
。
要获得您想要的行为,只需执行let start = Sys.time ()
,它将函数Sys.time
应用于参数()
(这是类型unit
的唯一值)。< / p>
答案 1 :(得分:3)
只能通过编写名称来调用函数。如果你只是写一个函数的名字,你将返回函数本身,而不是它的返回值。该错误告诉您函数采用unit
参数 - 即,您应该编写Sys.time ()
来实际应用函数并获得结果float
值。
答案 2 :(得分:0)
为了帮助人们习惯使用Lisp,我想说OCAML中只有两个评估规则:
fun x -> body
)将不再进行评估。 (函数体的评估是“延迟的”。)而是将表达式“body”编译成计算机代码。该计算机代码是函数表达式的真正“值”,只要函数应用于参数,代码就会运行。f x
时,首先评估参数x
。 (函数“渴望评估它们的参数”。)然后计算函数表达式f
,它通常产生一个函数值,例如fun x -> body
。 (这里,body
尚未评估;只有在评估我们得到函数值fun x -> body
时才会这样做。例如,f
可能是一个复杂的表达式,它产生如下函数值:结果。)最后,结果函数的主体应用于参数的实际计算值(即body
被评估,x
被参数的计算值替换。)出于这个原因,你可以在OCAML中实现“quote”,如果你想延迟某些表达式的评估,只需将它放在函数表达式的主体中。例如,如果您之前已根据f
计算let f = fun x->x+1
,现在您想延迟f 3
的评估,则可以将此f 3
放入函数体中:
let delay_f () = f 3;;
现在,只有在评估delay_f ()
时才会获得4。您可以将值delay_f
传递给另一个函数,f 3
将保持无评估,直到有人评估delay_f ()
。