簡體   English   中英

輸入函數式編程(OCaml)

[英]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個參數XY ,並輸出Z 我們通常的寫法是

f(X, Y) = Z

讓我們以不同的方式看待這一點-我們有一個函數f ,如果給它X ,然后給Y ,它將給我們Z 如果我們僅給f 1自變量X會發生什么? 讓我們測試一下!

let plus a b = a + b;;

這段代碼定義了一個plus函數,該函數接受2個參數ab並返回它們的總和。 如果鍵入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個參數nm ,並輸出函數f接受2個參數bx 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 ,而xsome number應該是int ,OCaml具有一個稱為類型推斷的功能 基本上,編譯器會查看您對變量執行的操作,並嘗試猜測它們的類型。 例如,我查看代碼中的if b ,所以b可能應該是bool

總而言之 ,寫函數簽名的晦澀方式被稱為currying ,而OCaml如何知道bbool是通過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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM