2011-05-13 35 views
15

我只知道F#。我還沒有學習其他函數式編程語言。我所見過的單子的所有例子只描述綁定和單元方法。 F#有很多關鍵字(例如let!,do!等),它們允許您在同一個計算表達式中執行不同的操作。這似乎給你比你的基本綁定和單位方法更多的權力。這對於F#來說是獨一無二的,還是在函數式編程語言中很常見?F#的monad實現是否與可用關鍵字的數量相關?

回答

18

是的,我認爲計算表達式的F#語法是獨一無二的,因爲它爲不同類型的計算提供了直接的語法支持。它可以用於與monoids,通常monads以及還有MonadPlus來自Haskell的計算。

我寫了關於這些在my Master thesis的介紹。我相信它是非常易讀的部分,所以你可以去第27頁閱讀它。無論如何,我將在這裏複製示例:

Monoid僅用於使用某些「+」操作(Combine)連接值。您可以使用它例如用於建築物的字符串(這是低效的,但它表明了想法):

type StringMonoid() = 
    member x.Combine(s1, s2) = String.Concat(s1, s2) 
    member x.Zero() = "" 
    member x.Yield(s) = s 

let str = new StringMonoid() 

let hello = str { yield "Hello " 
        yield "world!" };; 

單子是使用綁定回報comptuation表達操作熟悉的例子。例如也許單子表示計算,可以在任何點失敗:

type MaybeMonad() = 
    member x.Bind(m, f) = 
    match m with Some(v) -> f v | None -> None 
    member x.Return(v) = Some(v) 

let maybe = new MaybeMonad() 

let rec productNameByID() = maybe { 
    let! id = tryReadNumber() 
    let! prod = db.TryFindProduct(id) 
    return prod.Name } 

添加劑單子(又名在Haskell MonadPlus)是兩者的組合。它有點像單子計算,可以產生多個值。一個常見的例子是列表(或序列),它可以同時實現綁定結合

type ListMonadPlus() = 
    member x.Zero() = [] 
    member x.Yield(v) = [v] 
    member x.Combine(a, b) = a @ b 
    member x.Bind(l, f) = l |> List.map f |> List.concat 

let list = new ListMonadPlus() 

let cities = list { 
    yield "York" 
    yield "Orleans" } 
let moreCities = list { 
    let! n = cities 
    yield n 
    yield "New " + n } 

// Creates: [ "York"; "New York"; "Orleans"; "New Orleans" ] 

有一些不直接對應於任何理論概念的其他關鍵字。 use關鍵字處理資源,forwhile可用於實現循環。序列/列表理解實際上使用for而不是let!,因爲從句法的角度來看,它更有意義(並且for通常需要一些序列 - 雖然它可能是例如異步的)。

+0

托馬斯,上面的文件鏈接不再工作。這裏是新的鏈接,http://tomasp.net/academic/theses/events/events.pdf。 – kimsk 2014-12-15 08:10:42

5

monads根據bindunit操作(僅限於)進行定義。還有其他的結構由其他操作定義(例如,在Haskell中,MonadPlus類型類具有zeroplus操作 - 這些對應於F#計算表達式中的ZeroCombine)。據我所知,F#的計算構造器在爲它們所支持的各種操作提供很好的語法方面是獨一無二的,但大多數操作都與單子無關。

2

結尾爲!的F#綁定表示計算表達式,包括let! use! do! yield! return!

let! pat = expr in comp-expr   -- binding computation 

do! expr in comp-expr    -- sequential computation 

use! pat = expr in comp-expr   -- auto cleanup computation 

yield! expr       -- yield computation 

return! expr       -- return computation 

計算表達式用於「用於F#表達式語法的序列和其他非標準解釋」。這些語法形式提供了重載該語法的方式,例如,用於編碼一次性計算或單調計算,並且看起來與例如類似。 Haskell的do-notation以及該語言中的相應(非魔術)綁定形式。

所以我會說他們支持一些語法重載來支持對語言表達式語法的其他解釋,而這與他們與許多語言(包括Haskell和OCaml)都有相同之處。這當然是一個強大且有用的語言功能。


參考文獻:The F# 2.0 Language Specification

1

(從內存中調出,我可能會關閉。)

雖然我認爲unitbind是單子典型的基礎上,我想也許mapjoin爲基礎不同,我在學術論文見過。這有點像LINQ如何在C#和VB中工作,其中各種from語法解析爲SelectSelectMany,它們與mapjoin相似。 LINQ也有一些額外的關鍵字,有點像F#,雖然更特別(並且最適合查詢枚舉/數據庫)。我不知道像F#這樣的其他函數式語言如何將大部分控制流和其他語法有效地「提升」爲monad(以及「計算表達式」,其中可能是monads),但是我不知道。

+1

對於它的價值,「規範」的基礎將是地圖,單元和連接的全部三個;所有都是獨特和正交的,結果在數學上令人愉快。 「bind」操作是一個複合map +連接,只存在是因爲它在概念上更方便用monad編程 - 在LINQ的情況下,想象只用'Select'和'Concat'而不是'SelectMany'做所有事情。 – 2011-05-17 22:19:04

相關問題