我正在评估Ocaml中的一段非常简单的代码:
let p5 () = print_int 5;;
p5 ();;
print_string "*************************";;
let p4 = print_int 4;;
p4;;
它返回:
val p5 : unit -> unit = <fun>
# 5- : unit = ()
# *************************- : unit = ()
# 4val p4 : unit = ()
# - : unit = ()
我的问题是
()
中let p5 () = print_int 5;;
的含义是什么?-
中的()
和# 5- : unit = ()
是什么意思?p4
是函数吗?4
的开头有# 4val p4 : unit = ()
?()
来隐藏副作用,有人能给我看一个例子吗?答案 0 :(得分:11)
这里有一些答案:
()
是单位类型值。单位类型是只有一个值的类型。这通常用于生成函数,这些函数要么没有任何意义,要么没有任何意义。请记住,在OCaml中,所有函数总是必须返回一些东西并采取一些参数,因此单位类型用于解决此限制。可以认为这类似于C,C ++或Java中的void
类型。5
由print_int
函数打印,而不是由顶层打印。顶层只返回- : unit = ()
而没有5
。 toplevel告诉您它没有创建任何新绑定-
,并且最后返回的值是unit
类型,其值为()
。4
由print_int
函数打印。此时,toplevel告诉您,它创建了一个新的绑定p4
,该变量带有unit
类型的值,并且存储的值为()
。()
不用于隐藏副作用。它通常用于创建具有副作用的函数,因此不需要采取任何形式的论证。答案 1 :(得分:6)
LiKao已经解释了所有关键点,但我认为如果你一次输入一行定义可能更有意义,这将显示哪些响应来自哪些输入。此人输入的行以#
开头。
# let p5 () = print_int 5;;
val p5 : unit -> unit = <fun>
这将p5定义为接受类型unit
的值并返回类型unit
的值的函数。类型单位只有一个值,写为()
。所以这些正是你所询问的括号(我认为)。请注意,定义中出现的()
是函数接受的值的模式。作为模式,()
匹配自身(就像用作模式的所有常量一样)。
# p5 ();;
5- : unit = ()
这有点令人困惑。 5
由您的函数p5
编写。其余的是OCaml顶级的回应。它表示您的表达式的结果是unit
类型,其值为()
。这是有道理的,print_int
的类型为int -> unit
。
# print_string "*************************";;
*************************- : unit = ()
这里有类似的混淆。星号*
由print_string
编写。其余部分显示结果,该结果的类型为unit
,其值为()
。
# let p4 = print_int 4;;
4val p4 : unit = ()
这里也是一样的。 4
由print_int
撰写。其余部分显示顶级已定义名为p4
的符号,其类型为unit
,其值为()
。同样,这是有道理的,因为print_int
返回unit
类型,()
是该类型的唯一值。您可以从p4
的类型判断它是不是的函数。函数在类型中有一个箭头(->
)。 p4
只是unit
类型的值。
# p4;;
- : unit = ()
在这里,您向顶层询问p4
的类型和值,并告诉您(再次)p4
的类型为unit
,其值为{{1 }}
答案 2 :(得分:2)
你的最后一个问题是()
如何用来“隐藏副作用”。您可能指的是函数的延迟评估。这是一个例子:
let p x = print_string "abc";;
let q = print_string "abc";;
p
和q
之间存在重大差异。区别在于p
是'a -> unit
类型的函数,而q
是类型unit
的值。定义p
时,不会打印任何内容。仅当您将函数p
应用于参数时,即当您评估p 1
或p "blah"
或其他任何内容时,才会打印字符串“abc”。 (函数p
接受任何类型的参数并忽略它们。)因此,在p
的情况下,你在函数内部“隐藏了副作用”。
在“p x”的定义中有一个参数“x”是没有意义的,因为根本不使用“x”。因此,为简单起见,使用“单位”类型,因此“p”的定义看起来像“let p()= ......”。这与
相同 let p = fun () -> print_string "abc";;
然后将函数“p”用作“p()”。如果您第一次学习编程语言(如C,Java等),其中()用于所有函数的参数,这可能会令人困惑。但在OCAML中,()
是一个表示“空值”的特殊符号,该值具有一个称为“单位”的特殊类型。
定义q
时会发生完全不同的事情:立即打印字符串“abc”,因为这是评估“print_string”的副作用,q
变得等于{ {1}},因为()
是通过评估“print_string”获得的结果值。
答案 3 :(得分:0)
我迟到了,但我想指出在
中使用()
let p5 () = print_int 5
在p5
的参数中有一个模式匹配。它相当于:
let p5 x = match x with () -> print_int 5
或者这个:
let p5 = function () -> print_int 5
甚至这个:
let p5 = fun x -> match x with () -> print_int 5
这种区别在以下代码中很重要:
let f (x, y) = print_int (x + y)
let g x y = print_int (x + y)
f
只收到一个参数((x, y)
对),而g
收到两个参数。因此f
类型为(int * int) -> unit
,g
类型为int -> int -> unit
。所以f
可以这样写:
let f pair = match pair with (x, y) -> print_int (x + y)