簡體   English   中英

Lambda表達式在Scheme中是單子嗎?

[英]Lambda expressions as monads in Scheme?

我在網上閱讀了一些文檔,這些文檔試圖為Scheme程序員介紹monad的概念。 核心思想是在非命令式編程中,monad用於表示“計算流”,即強制執行表達式的順序求值。 然后讓我震驚:既然lambda表達式的主體是按順序求值的,那么人們是否應該理解Monad在Scheme中是多余的? 在其他語言(例如,Haskell或ML)中,lambda主體的評估是否有所不同?

順序評估

因此,表達式的順序求值不是monad的特征,而是函數的特征 從您寫出f (gx) (Haskell)或(f (gx)) (方案)的那一刻起,您就已經將g排序為發生在f之前。 相反,在Haskell中,我們使用(then fg)(bind f (lambda (x) (make-g x)))類的序列運算符來執行此操作,但是您可以根據需要執行此操作。

困惑是:monad至少在Haskell中帶有通用表示法 ,並且該通用表示法將語句按命令順序放置。 從Scheme的角度來看,這是一個宏do ,它重寫:

(do
    (put-string "Hey, what's your name?")
    (into x get-line)
    (put-string (string-append "Hi, " x "!")))

(then 
    (put-string "Hey, what's your name?")
    (bind get-line (lambda (x) 
        (put-string (string-append "Hi, " x "!")))))

請注意,lambda被“展平”並替換為一些新符號“ into”。 (實際上,在Haskell中,我們會說“ from”,但這是一個中綴運算符,而不是前綴運算符。)

什么是單子

那么,什么單子呢? 好吧,首先,讓我們定義它們的詞性:單子形容詞 ,就像形容詞“ blue”一樣。 我可以有藍色的馬車或藍色的車輪。 Monad是函子 ,這意味着從旅行車到其輪子的功能,我可以為您提供從藍色旅行車到其藍色輪子的功能。 因此功能可以“在其下操作”。 但是monad具有兩個特殊屬性。 首先,我們有一個只適用於“藍色”的想法,如果我們使該想法變得異常抽象和形而上的話 :形容詞必須能夠應用於語言中的任何值 因此,您不僅擁有藍色的旅行車和藍色的輪子,而且擁有藍色的功能和打印“ Hello,World!”的藍色程序。 到屏幕上,藍變一切。 第二個形容詞在某種意義上必須是可壓縮的,因為給定一個藍色的藍色旅行車,您可以給我一個藍色的旅行車。

做到這一點的形容詞是“可為空...”。 您始終可以獲取任何值,並根據該值生成一個新的可為空的值:只需開始接受和檢測空值! 如果您使用的是默認情況下不能為空的靜態類型語言,那么這很重要。 這個形容詞是一個函子:給定一個函數,我們只是將null轉換為null,然后使用該函數進行任何其他轉換。 這是可壓縮的,因為如果我們有一個“可為空的可為空字符串”可簡化為可為空的字符串:將“ null”和“ not-null null”值分別設置為“ null”,將“ not-null not-null字符串”設置為“非空字符串”。 最后,要將任何字符串表示為可為空的字符串,請將其轉換為“非空字符串”。 這稱為Maybe monad。 實際上,這是Either y monad的特殊情況,可以容納y

這樣做的另一個形容詞是“ ...的列表”。 要在形容詞下應用功能,請將其應用到列表的所有成員。 要將列表列表壓縮為列表,請串聯其元素。 要從任何x創建x的列表,請給我返回一個元素列表。 這稱為“列表單子”。 這種寫法很像寫列表推導,實際上與Clojure換能器是同構的,因此您可以免費獲得地圖和過濾器。

這樣做的另一個形容詞是“從s到s和a ...的函數”。 要從任何x創建其中之一,只需將傳入狀態與x配對。 要應用功能,只需將其應用到輸出對的相應一側即可。 十分簡單。 最后,如果您遇到了復雜的s -> (s, s -> (s, a))情況,則通過將傳入的s饋送給被卷積的函數來構造s -> (s, a) ,並取出出現的s然后將其饋送到其中的s -> (s, a)中。 這為您提供了您需要返回的(s, a) 這被稱為“ State s monad”,因為您可以將“ s”設想為類型化狀態。

執行此操作的另一個形容詞是“返回a的程序”。 如果您有一個int,我們可以構建一個不執行任何操作並返回該int的程序。 如果您有一個將int和函數從int返回到其他函數的程序,我們可以執行該程序,然后將該函數應用於程序的輸出。 最后,如果您擁有“一個程序返回一個程序,該程序返回一個int”,則只需形成一個程序,該程序運行外部程序以計算內部程序,然后運行內部程序。 這稱為IO x monad。 (與承諾類似:承諾的x與承諾的x沒有太大區別。)

您會看到這是一個非常廣泛的模式,並且並不總是清楚地涉及“序列”。

與Haskell的比較方案

一旦了解了Haskell通過將程序作為值並將它們組合在一起來描述了其所有I / O操作,您就會意識到,基本上我們是通過成為一種宏語言來進行功能性I / O的 宏語言本身不會執行任何 I / O,但是您可以使用它來構造為您執行I / O的程序。 您將它們輸入到編譯器中,然后編譯器將生成實際程序,該程序可以執行您想要的操作。 口譯員會獲得更多選擇,因為口譯員需要說“如果我看到一個不是程序的值,我將嘗試打印該值;如果我看到一個不是程序的值, 我將嘗試運行該程序,然后打印出來。” 這意味着命令提示符下的語法與文件中的語法略有不同。

一旦了解了Haskell是我們在構建程序即價值的元編程環境后,您將了解Haskell如何執行功能性I / O,並且您會看到“ monads”的可編程語法是元元編程設計。 這種設計比宏(在Haskell中也有它;它被稱為“ Template Haskell”)要復雜得多,但是可以在很多有用的情況下完成工作。 從本質上講,這是關於在某種程度上重載“ a; b; c; d”意味着要依賴於a,b,c和d類型的(通用)最外面的形容詞。 對於I / O,它的意思是“先執行a,然后執行b,然后...”; 對於狀態,它的意思是“將a產生的狀態放入b,然后b產生的狀態放入c,然后...”; 對於nullable來說,它的意思是“執行a,如果不是null,則使用它執行b,如果不是null,則使用它執行c ...”。 對於列表,它是構成列表的笛卡爾乘積,“以所有方式配對所有內容”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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