Ocaml中的括号

时间:2011-10-10 10:10:22

标签: ocaml

我正在评估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 = ()

我的问题是

  1. ()let p5 () = print_int 5;;的含义是什么?
  2. -中的()# 5- : unit = ()是什么意思?
  3. p4是函数吗?
  4. 为什么4的开头有# 4val p4 : unit = ()
  5. 似乎可以在Ocaml代码中使用()来隐藏副作用,有人能给我看一个例子吗?

4 个答案:

答案 0 :(得分:11)

这里有一些答案:

  1. ()是单位类型值。单位类型是只有一个值的类型。这通常用于生成函数,这些函数要么没有任何意义,要么没有任何意义。请记住,在OCaml中,所有函数总是必须返回一些东西并采取一些参数,因此单位类型用于解决此限制。可以认为这类似于C,C ++或Java中的void类型。
  2. 有两行交错。 5print_int函数打印,而不是由顶层打印。顶层只返回- : unit = ()而没有5。 toplevel告诉您它没有创建任何新绑定-,并且最后返回的值是unit类型,其值为()
  3. 否。它不需要任何参数,因此它不是一个函数。
  4. 同样有两行交错。 4print_int函数打印。此时,toplevel告诉您,它创建了一个新的绑定p4,该变量带有unit类型的值,并且存储的值为()
  5. 不,()不用于隐藏副作用。它通常用于创建具有副作用的函数,因此不需要采取任何形式的论证。

答案 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 = ()

这里也是一样的。 4print_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";;

pq之间存在重大差异。区别在于p'a -> unit类型的函数,而q是类型unit的值。定义p时,不会打印任何内容。仅当您将函数p应用于参数时,即当您评估p 1p "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) -> unitg类型为int -> int -> unit。所以f可以这样写:

let f pair = match pair with (x, y) -> print_int (x + y)