2011-10-10 67 views
5

我在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. 爲什麼在# 4val p4 : unit =()的開頭有4
  5. 看來()可以在Ocaml代碼中用來隱藏副作用,任何人都可以給我一個例子嗎?
+1

'print_endline',而不是'print_string'因爲它會自動打印後的底線 – newacct

回答

11

這裏一些答案:

  1. ()是單元類型值。單位類型是隻有一個值的類型。這通常用於產生無意義或無意義的函數。請記住,在OCaml中,所有函數都必須返回一些內容並採取一些參數,因此單位類型用於解決此限制。可以考慮類似於C,C++或Java中的void類型。
  2. 有兩行交錯。 5print_int函數打印,而不是由頂層打印。頂層只是返回- : unit =()沒有5。頂層告訴你,它沒有創建任何新的綁定-,最後返回的值是unit類型,其值爲()
  3. 不會。它沒有任何參數,所以它不是一個函數。
  4. 再次有兩行交錯。 4print_int函數打印。此時,頂層告訴你,它創建了一個新的綁定p4,該變量的值爲unit,存儲的值爲()
  5. 不,()不用於隱藏副作用。它通常用於創建具有副作用的函數,因此不需要採取任何形式的論證。
6

LiKao已經解釋了所有的關鍵點,但是我認爲如果您一次一行地輸入您的定義,這將顯示哪些回答來自哪些輸入,這可能會更有意義。該人輸入的行從#開始。

# let p5() = print_int 5;; 
val p5 : unit -> unit = <fun> 

這P5定義爲接受unit類型的值,並返回unit類型的值的函數。類型單位只有一個值,寫爲()。所以這些就是你問的括號(我認爲)。請注意,出現在您的定義中的()是該函數接受的值的模式。作爲一種模式,()匹配自身(就像所有用作模式的常量)。

# p5();; 
5- : unit =() 

這有點令人困惑。 5由您的函數p5編寫。其餘的是OCaml頂級響應。這是說你的表情的結果是unit類型,其值爲()。它是有道理的,print_intint -> 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價值,而且它(再次)告訴你p4unit類型的並具有價值()

2

您最後的問題是如何使用()「隱藏副作用」。您可能指的是功能的延遲評估。這裏有一個例子:

let p x = print_string "abc";; 
let q = print_string "abc";; 

pq之間的關鍵區別。區別在於p是類型'a -> unit的函數,而q是類型unit的值。當您定義p時,不會打印任何內容。字符串「abc」僅在您將函數p應用於參數時纔會打印,即,當您評估p 1p "blah"或其他任何內容時。 (函數p需要任何類型的參數並忽略它們。)因此,在p的情況下,您在函數內部「隱藏了一個副作用」。

在「p x」的定義中有一個參數「x」是沒有意義的,因爲根本不使用「x」。所以爲了簡單起見,使用「unit」類型,以便「p」的定義看起來像「let p()= ...」。這與

let p = fun() -> print_string "abc";; 

函數「p」然後被用作「p()」。如果您第一次學習像C,Java等編程語言,其中()用於所有函數的參數,這可能會引起混淆。但在OCAML中,()是一個表示「空值」的特殊符號,該值有一個稱爲「單位」的特殊類型。

一個完全不同的事情發生在定義q:字符串「abc」被印刷向右走,因爲這是評估「print_string」的副作用,和q變得等於(),由於()是所得到的值通過評估「print_string」獲得。

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) 
你可能要習慣使用