[英]Type in functional programming (OCaml)
我正在學習函數式編程,並且不了解OCaml中的類型,並且我還沒有發現真正有用的東西。
我有以下代碼:
let rec map2 f l1 l2 =
match (l1,l2) with
([], _) -> []
| (_, []) -> []
| (x::l1s,y::l2s) -> (f x y) :: map2 f l1s l2s;;
let pick n m =
if n > m then (fun b x -> if b then x+1 else x*2)
else (fun b x -> if b then x+2 else x*4);;
map2 (pick 7 9) [true;false] [3;4;5;6];;
我發現很難理解了解此類功能類型的步驟(map2,pick)。
我知道一點點的簽名是如何工作的,正確的關聯屬性和符號“'”指的是一個泛型類型。
解:
pick: 'a -> 'a -> bool -> int -> int = <fun>
map2: ('a->'b->'c) -> 'a list -> 'b list -> 'c list
我不明白為什么bool-> int以及為什么map bool不在函數參數中。
任何對書籍,鏈接的引用都歡迎
pick: 'a -> 'a -> bool -> int -> int = <fun>
map2: ('a->'b->'c) -> 'a list -> 'b list -> 'c list
您在這里看到的是函數編程中稱為currying的過程 。 為了理解這一點,讓我們考慮一個更簡單的示例。 假設您有一個函數f
,它接受2個參數X
和Y
,並輸出Z
我們通常的寫法是
f(X, Y) = Z
讓我們以不同的方式看待這一點-我們有一個函數f
,如果給它X
,然后給Y
,它將給我們Z
如果我們僅給f
1自變量X
會發生什么? 讓我們測試一下!
let plus a b = a + b;;
這段代碼定義了一個plus
函數,該函數接受2個參數a
和b
並返回它們的總和。 如果鍵入plus 1 1;;
進入utop
,它將給您2
。 現在,鍵入時的輸出
plus 1;;
是
- : int -> int = <fun>
這意味着plus(1)
實際上會產生一個函數,該函數接受一個int
並輸出一個int
! 等一下,最初我們有一個產生整數的函數,突然之間,同一函數產生了...功能? 這是怎么回事?
這里的關鍵思想是將函數視為一個過程,該過程一個接一個地消耗參數 。 在這種精神的功能plus
上面就是這樣消耗2個參數的方法:如果你給它只是1周的說法,這將拖延和等待第二個參數。 這個停頓的過程與消耗1個參數的過程完全相似:給它剩余的成分,它將開始磨碎以提供預期的輸出。
為了了解這種觀點如何幫助您理解示例中編寫函數簽名的晦澀方式,讓我們看一下函數pick
:
let pick n m =
if n > m then (fun b x -> if b then x+1 else x*2)
else (fun b x -> if b then x+2 else x*4);;
pick
接受2個參數n
和m
,並輸出函數f
接受2個參數b
和x
。 f
的定義取決於比較。 如果n > m
,則它輸出一個函數fun bx
其定義是if b then x+1 else x*2
。 否則,它輸出一個函數fun bx
其定義是if b then x+2 else x*4
。
如果我們根據上述理解為pick
寫一個粗略的簽名,它將類似於:
pick: (n, m) -> (function f that takes in b and x, and output some number)
根據我們對curring的理解, pick
就像一個消耗n
,然后消耗m
。 所以簽名也可以這樣寫:
pick: n -> m -> (function f that takes in b and x, and output some number)
哦,嘿,這個函數f
也可以看作是一個先消耗b
然后再消耗x
的進程,所以我們也可以這樣寫:
pick: n -> m -> (b -> x -> some number)
看起來非常類似於:
pick: 'a -> 'a -> bool -> int -> int = <fun>
現在,關於OCaml到底是怎么知道b
應該是bool
,而x
和some number
應該是int
,OCaml具有一個稱為類型推斷的功能 。 基本上,編譯器會查看您對變量執行的操作,並嘗試猜測它們的類型。 例如,我查看代碼中的if b
,所以b
可能應該是bool
。
總而言之 ,寫函數簽名的晦澀方式被稱為currying ,而OCaml如何知道b
是bool
是通過OCaml中的一種稱為類型推斷的特征來實現的。 這應該使搜索更容易。
如果查看pick,則會看到它接受2個參數,然后返回一個函數。 它返回的是(與其他樂趣相同):
(fun b x -> if b then x+1 else x*2)
“ if”構造的形式為if <bool> then <'a> else <'a>
。 所以b必須是布爾值,而x仍然可以是'a。 更深入的是x+1
。 所以x必須int
,結果是int
了。
因此,上面的函數是bool -> int -> int
並且在pick類型中顯示hat。
至於map2:map2函數可以使用形式為'a -> 'b -> 'c
任何函數作為第一個參數。 在您的示例中,您傳遞了bool -> int -> int
但這並不將map2限制為該類型。 您的代碼可以繼續
let pick_f n m =
if n > m then (fun b x -> if b then x +. 1. else x *. 2.)
else (fun b x -> if b then x +. 2. else x *. 4.);;
map2 (pick_f 7 9) [true;false] [3.;4.;5.;6.];;
pick_f: 'a -> 'a -> bool -> float -> float = <fun>
使用相同的map2函數,但此處將bool -> float -> float
作為第一個參數的類型。 map2函數是多態的(您稱為泛型),可以使用許多類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.