Ocaml中的括号

Ocaml中的括号,ocaml,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

我正在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 = ()
val p5:unit->unit=
#5-:单位=()
#*********************-:单位=()
#4val p4:单位=()
#-:单位=()
我的问题是

  • let p5()=print_int 5;中,
    ()
    是什么意思
  • #5-:unit=()
    -
    ()
    是什么意思
  • p4
    是一种功能吗
  • 为什么在
    #4val p4:unit=()
    的开头有
    4
  • 似乎可以在Ocaml代码中使用
    ()
    来隐藏副作用,有人能给我举个例子吗
  • 以下是一些答案:

  • ()
    是单位类型值。单位类型是只有一个值的类型。这通常用于生成要么不返回任何有意义的函数,要么不获取任何有意义的函数。请记住,在OCaml中,所有函数都必须返回一些内容并接受一些参数,因此使用单元类型来绕过此限制。在C、C++或java中,类似于 Value/Cuff>类型。
  • 有两行交错排列。
    5
    print_int
    功能打印,而不是由顶层打印。顶层只返回
    -:unit=()
    ,而不返回
    5
    。toplevel告诉您它没有创建任何新的绑定
    -
    ,最后返回的值是
    单元类型的
    ,并且具有值
    ()
  • 不,它不接受任何参数,所以它不是一个函数
  • 又有两行交错。
    4
    print\u int
    功能打印。此时,toplevel告诉您,它创建了一个新的绑定
    p4
    ,该变量携带的值类型为
    unit
    ,存储的值为
    ()
  • 不,
    ()
    不用于隐藏副作用。它通常用于创建具有副作用的函数,因此不需要接受任何类型的参数

  • LiKao已经解释了所有的关键点,但我认为如果你一次只输入一行定义,这会显示哪些响应来自哪些输入,可能更有意义。此人输入的行以
    #
    开头

    这有点令人困惑。
    5
    由函数
    p5
    编写。其余部分是来自OCaml顶层的响应。这意味着表达式的结果是类型
    unit
    ,并且具有值
    ()
    。有道理,
    print\u int
    int->unit
    类型

    # print_string "*************************";;
    *************************- : unit = ()
    
    # p4;;
    - : unit = ()
    
    这里也有类似的困惑。星号
    *
    print\u string
    写入。其余部分显示结果,其类型同样为
    unit
    ,值为
    ()

    这里也一样。
    4
    print\u int
    编写。其余部分显示顶层定义了一个名为
    p4
    的符号,其类型为
    unit
    ,其值为
    ()
    。同样,这是有意义的,因为
    print\u int
    返回
    unit
    类型,并且
    ()
    是该类型的唯一值。从
    p4
    的类型可以看出它不是一个函数。函数的类型中有一个箭头(
    ->
    p4
    只是
    unit
    类型的值

    # print_string "*************************";;
    *************************- : unit = ()
    
    # p4;;
    - : unit = ()
    

    在这里,您向顶层询问
    p4
    的类型和值,它(再次)告诉您
    p4
    属于
    unit
    类型,并且具有
    ()
    值。最后一个问题是如何使用
    ()
    来“隐藏副作用”。您可能指的是函数的延迟求值。以下是一个例子:

     let p x = print_string "abc";;
     let q = print_string "abc";;
    
    p
    q
    之间有着至关重要的区别。区别在于
    p
    'a->unit
    类型的函数,
    q
    unit
    类型的值。定义
    p
    时,不会打印任何内容。仅当您将函数
    p
    应用于参数时,即当您计算
    p1
    p“blah”
    或任何值时,才会打印字符串“abc”。(函数
    p
    接受任何类型的参数并忽略它们。)因此在
    p
    的情况下,您在函数内部“隐藏了一个副作用”

    在“px”的定义中,有一个参数“x”是没有意义的,因为“x”根本不用。为了简单起见,使用了类型“unit”,因此“p”的定义看起来像“let p()=…”。这和

     let p = fun () -> print_string "abc";;
    
    然后将函数“p”用作“p()”。如果您首先学习了C、Java等编程语言,其中()用于所有函数的参数,那么这可能会令人困惑。但在OCAML中,
    ()
    是一个表示“空值”的特殊符号,该值有一个称为“单位”的特殊类型


    定义
    q
    时会发生完全不同的事情:字符串“abc”立即打印,因为这是计算“print\u string”的副作用,
    q
    等于
    ()
    ,因为
    ()
    是通过计算“print\u string”得到的结果值。

    我迟到了,但我想指出的是,在

    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)
    

    您可能希望习惯使用
    print\u endline
    而不是
    print\u string
    ,因为它可以自动
    let f pair = match pair with (x, y) -> print_int (x + y)