2007-04-02-haskell的世界觀

我的理解娱两,haskell創(chuàng)造了一個no side-effect的pure functional的world,然后為了和real world協(xié)同式散,創(chuàng)造了monad來封裝real world中的dirty data坝茎。

圖1 左邊是無副作用世界拱烁,右邊是真實世界,二者通過交換單子進行協(xié)同

當real world中發(fā)生一個destructive update的時候(輸入)崩哩,它把這個update一刻的瞬間snapshot下來巡球,產生一個monad;這個monad隨即被送往no side-effect world(下簡稱pure world)邓嘹。
pure world從單子中取出數據酣栈,進行運算,這個過程是pure的汹押。處理完成后矿筝,它把結果封裝成一個新的單子返回給真實世界,真實世界再發(fā)生一次destructive update(輸出)棚贾。

一個Monad m定義了一個運算(computation):



圖中上面一個是monad m a窖维,下面一個是function (a->m b)。
可以大致這么理解妙痹,一個monad是包含兩面的铸史,它除了在一個世界中作為a以外,還攜帶了另外一個世界如何從in變化到out的信息怯伊。所以琳轿,一個monad還叫做action,或者computation耿芹。例如崭篡,IO monad又稱IO action。后面為了不用每次畫圖猩系,我們這樣畫一個monad:
a//in->out媚送,或者a//in,或者a//out
而a->m b這樣畫:
a->b//in->out

Monad有四個基本運算分別是:bind(>>=), then(>>), return, fail寇甸。


從數學的角度講塘偎,一個monad只需要兩個運算疗涉,>>=和return就夠了。不過從程序設計角度吟秩,為了便利咱扣,添加了>>和fail,他們分別是>>=和return的特化型涵防。

bind運算把一個monad m a的pure部分取出來闹伪,放到一個monad constructor (a->m b)中,構造器產生一個新的monad m b壮池,借此把a輸送給real world偏瓤。
then運算是特殊的bind,它描述了兩個monad的順序誕生椰憋。
return運算是一個特殊的constructor厅克,它接受一個pure world中的a,產生一個monad m a橙依。
fail運算是特殊的return证舟,它接受一個String之后,產生一個monad窗骑,同時把這個String輸送給real world女责。

monad三定律:
(1) return a >>= k == k a
(2) m >>= return == m
(3) m >>= (/x -> k x >>= h) == (m >>= k) >>= h

第一個,monad bind到constructor等價于直接apply monad中的pure部分到constructor创译。
第二個抵知,return保留monad的所有信息不變。
第三個昔榴,bind運算滿足結合律辛藻。

好了,看了這么些難以理解的概念之后互订,讓我們看看幾個實際的例子吧吱肌。

  1. putStrLn :: String -> IO ()
    putStrLn函數根據pure world中的一個String構造了一個IO monad IO ()。

  2. Just :: a -> Maybe a
    Just這個constructor根據a構造一個Maybe monad Maybe a仰禽。
    試試把一個Maybe monad bind到print看看:
    Prelude> (Just 3)>>=print
    Couldn't match expected type Maybe' against inferred typeIO'
    Expected type: t -> Maybe b
    Inferred type: t -> IO ()
    看起來氮墨,monad只能bind到能夠構造同類型monad的constructor上。
    Prelude> let f x | x>=0 = Just (x+1) | x<0 = Nothing
    Prelude> :t ff :: (Ord a, Num a) => a -> Maybe a
    Prelude> (Just 3)>>=f
    Just 4
    Prelude> (Just (-1))>>=f
    Nothing
    進一步看看:
    Prelude> :t f 3
    f 3 :: (Ord t, Num t) => Maybe t
    Prelude> :t f (-1)
    f (-1) :: (Ord a, Num a) => Maybe a
    可以看到吐葵,real world中不是只有I/O一種action规揪。

  3. rollDice = getStdRandom (randomR (1,6)) :: IO Integer
    這是一個隨機數產生函數。
    試試看:
    Prelude> :m System.Random
    Prelude System.Random> let rollDice = getStdRandom(randomR(1,6))
    Prelude System.Random> mapM (/x->rollDice) [1..12]
    [3,5,3,6,2,4,5,1,5,6,3,2]

為什么monad的引入就能夠把pure world和real world和諧的結合起來呢温峭?
rollDice函數不是不符合“給出相同的參數猛铅,返回相同的結果”么?

我們先來看看pure function的定義吧:
wikipedia上是這么寫的:
In computer programming, a function may be described as pure if both these statements about the function hold.

  1. The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change as program execution proceeds, nor can it depend on any external input from IO devices.
  2. Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to IO devices.

翻譯一下就是:

  1. 給出相同的參數凤藏,函數總是求值出相同的結果奸忽。結果不能依賴于任何在程序運行過程中可能改變的隱含的信息或者狀態(tài)堕伪,也不能依賴于任何外部輸入例如IO設備。
  2. 對結果的求值不能導致任何語義上可以觀察到的副作用或者輸出栗菜,例如可變對象的改變或者IO設備上的輸出欠雌。

結論是顯然的但又是令人困惑的,rollDice不是pure的疙筹?富俄!
但是haskell作為一個pure functional語言是不允許定義impure的function的。
矛盾6亍霍比?

其實,因為有了monad和lazy evaluation暴备,這個矛盾便得以調和桂塞。
還記得rollDice的類型吧:rollDice :: IO Integer//rand(1,6)
你說它是一個monad也好,說它是一個制造monad的函數也好馍驯,請記住,函數是一類公民玛痊!
好汰瘫,注意這里,我們并不需要rollDice的結果擂煞,因為現在用不到混弥。

然后,我們把它放到了一個mapM里面去運算:
mapM (/x->rollDice) [1..12]
用rollDice構造出來的函數(/x->rollDice)是:t->IO Integer//rand(1,6)

看看mapM是干什么的吧: mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]好啦对省,mapM由[1..12]得到了一個新的monad IO [Integer]//rand(1,6) repeat 12
我們還是不需要求值蝗拿。

現在,該把這個monad從pure world扔到real world了蒿涎,我們使用print :: a -> IO ()
(mapM (/x->rollDice) [1..12])>>=print
monad IO [Integer]把它的[Integer]部分交給了print哀托,bind之后得到了一個新的monad IO ()//print rand(1,6) repeat 12 to stdout

real world不是lazy的,它計算了12次rand(1,6)劳秋,然后把它們打印到了終端上仓手,于是我們的終端上立刻顯示出了諸如[6,6,2,6,5,3,1,3,6,4,2,5]之類的數列。

回過頭來看一看玻淑,rollDice嗽冒、mapM、print之類的函數是pure function嗎补履?
答案是——yes添坊!

在pure world,函數是lazy的箫锤。rollDice每次調用都會返回IO rand(1,6),在純函數世界里,這不過就是一個名字"rand(1,6)"而已卖陵;而這個monad卻同時定義了真實世界里的一個計算拍霜,那就是計算1~6之間的一個隨機數。當把這個monad從pure world扔到real world之后坎穿,real world便進行強制求值,于是就得到了一個隨機數。

lazy要call by name岔擂,計算name,返回name浪耘。strict要call by value乱灵,計算value,返回value七冲。這就是haskell的純函數世界和真實世界最大的不同痛倚。

Haskell de facto describes a quantum world.
-- St. Monad

先講一個故事吧,薛定諤的貓(Schrodinger's cat)的故事澜躺。這是關于量子理論的一個理想實驗蝉稳。

這個貓十分可憐,她(假設這是一只雌性的貓掘鄙,以引起更多憐憫)被封在一個密室里耘戚,密室里有食物有毒藥。毒藥瓶上有一個錘子操漠,錘子由一個電子開關控制收津,電子開關由放射性原子控制。如果原子核衰變浊伙,則放出阿爾法粒子撞秋,觸動電子開關,錘子落下嚣鄙,砸碎毒藥瓶吻贿,釋放出里面的氰化物氣體,雌貓必死無疑哑子。這個殘忍的裝置由薛定諤所設計廓八,所以雌貓便叫做薛定諤貓。原子核的衰變是隨機事件赵抢,物理學家所能精確知道的只是半衰期——衰變一半所需要的時間剧蹂。如果一種放射性元素的半衰期是一天,則過一天烦却,該元素就少了一半宠叼,再過一天,就少了剩下的一半。但是冒冬,物理學家卻無法知道伸蚯,它在什么時候衰變,上午简烤,還是下午剂邮。當然,物理學家知道它在上午或下午衰變的幾率——也就是雌貓在上午或者下午死亡的幾率横侦。如果我們不揭開密室的蓋子挥萌,根據我們在日常生活中的經驗,可以認定枉侧,雌貓或者死引瀑,或者活。這是她的兩種本征態(tài)榨馁。但是憨栽,如果我們用薛定諤方程來描述薛定諤貓,則只能說翼虫,她處于一種活與不活的疊加態(tài)屑柔。我們只有在揭開蓋子的一瞬間,才能確切地知道雌貓是死是活珍剑。此時锯蛀,貓的波函數由疊加態(tài)立即收縮到某一個本征態(tài)。量子理論認為:如果沒有揭開蓋子次慢,進行觀察,我們永遠也不知道雌貓是死是活翔曲,她將永遠到處于半死不活的疊加態(tài)迫像。這與我們的日常經驗嚴重相違,要么死瞳遍,要么活闻妓,怎么可能不死不活,半死半活掠械?

薛定諤挖苦說:按照量子力學的解釋由缆,箱中之貓?zhí)幱凇八溃畀B加態(tài)”——既死了又活著!要等到打開箱子看貓一眼才決定其生死猾蒂。(請注意均唉!不是發(fā)現而是決定,僅僅看一眼就足以致命6遣ぁ)正像哈姆雷特王子所說:“是死舔箭,還是活,這可真是一個問題〔惴觯”只有當你打開盒子的時候箫章,迭加態(tài)突然結束(在數學術語就是“坍縮(collapse)”),哈姆雷特王子的猶豫才終于結束镜会,我們知道了貓的確定態(tài):死檬寂,或者活。哥本哈根的幾率詮釋的優(yōu)點是:只出現一個結果戳表,這與我們觀測到的結果相符合桶至。但是有一個大的問題:它要求波函數突然坍縮。但物理學中沒有一個公式能夠描述這種坍縮扒袖。盡管如此塞茅,長期以來物理學家們出于實用主義的考慮,還是接受了哥本哈根的詮釋季率。付出的代價是:違反了薛定諤方程野瘦。這就難怪薛定諤一直耿耿于懷了。

哥本哈根詮釋在很長的一段時間成了“正統(tǒng)的”飒泻、“標準的”詮釋鞭光。但那只不死不活的貓卻總是像惡夢一樣讓物理學家們不得安寧。格利賓在《尋找薛定諤的貓》中想告訴我們的是泞遗,哥本哈根詮釋在哪兒失敗惰许,以及用什么詮釋可以替代它。

1957年史辙,埃弗雷特提出的“多世界詮釋”似乎為人們帶來了福音汹买,雖然由于它太離奇開始沒有人認真對待。格利賓認為聊倔,多世界詮釋有許多優(yōu)點晦毙,由此它可以代替哥本哈根詮釋。我們下面簡單介紹一下埃弗雷特的多世界詮釋耙蔑。

格利賓在書中寫道:“埃弗雷特……指出兩只貓都是真實的见妒。有一只活貓,有一只死貓甸陌,但它們位于不同的世界中须揣。問題并不在于盒子中的放射性原子是否衰變,而在于它既衰變又不衰變钱豁。當我們向盒子里看時耻卡,整個世界分裂成它自己的兩個版本。這兩個版本在其余的各個方面都是全同的牲尺。唯一的區(qū)別在于其中一個版本中劲赠,原子衰變了,貓死了;而在另一個版本中凛澎,原子沒有衰變霹肝,貓還活著∷芗澹”

也就是說沫换,上面說的“原子衰變了,貓死了最铁;原子沒有衰變讯赏,貓還活著”這兩個世界將完全相互獨立地演變下去,就像兩個平行的世界一樣冷尉。格利賓顯然十分贊賞這一詮釋漱挎,所以他接著說:“這聽起來就像科幻小說,然而……它是基于無懈可擊的數學方程雀哨,基于量子力學樸實的磕谅、自洽的、符合邏輯的結果雾棺〔布校”“在量子的多世界中,我們通過參與而選擇出自己的道路捌浩。在我們生活的這個世界上放刨,沒有隱變量,上帝不會擲骰子尸饺,一切都是真實的进统。”按格利賓所說浪听,愛因斯坦如果還活著螟碎,他也許會同意并大大地贊揚這一個“沒有隱變量,上帝不會擲骰子”的理論馋辈。

這個詮釋的優(yōu)點是:薛定諤方程始終成立,波函數從不坍縮倍谜,由此它簡化了基本理論迈螟。它的問題是:設想過于離奇,付出的代價是這些平行的世界全都是同樣真實的尔崔。這就難怪有人說:“在科學史上答毫,多世界詮釋無疑是目前所提出的最大膽、最野心勃勃的理論季春∠绰В”

讀過大學物理的人大概都能夠想起來這個故事。

haskell里的monad就好像故事里的這只小貓:當它在pure functional的世界被構造出來之后,尚未進入真實世界的時候耘拇,它就仿佛處于一個“波函數疊加”的狀態(tài)撵颊,當其一進入真實世界——也就是被我們所“觀察”的時候——“波函數”就坍塌了,“生死得以確知”——副作用得以發(fā)生惫叛。

拿之前所舉的隨機數的函數rollDice來說倡勇,其中的rand(1,6)在我們還沒有“觀察”它的時候,它既不是1嘉涌,也不是2妻熊,也不是3,也不是4仑最,也不是5扔役,也不是6,它其實是以在1~6都可能的概率存在——描述這個概率的“波函數”是確定的警医,所以之前我說亿胸,rollDice :: IO Integer//rand(1,6)是pure function。為什么法严?因為rand(1,6)是一個“波函數”损敷,這個“波函數”是確定的,所以rollDice函數每次都會返回同一個“波函數”深啤,而這個“波函數”此刻并未被求值拗馒,因此說rollDice是完全符合pure function的定義的。

“波函數”就是monad對真實世界的描述溯街,它用確知的方程式描述不確知的真實世界诱桂。

一切為了和諧。

ps, 巧的是呈昔,還真有人用平行世界的觀點來詮釋haskell的世界觀挥等,看來也是不希望薛定諤方程被違背的人呀!哈哈堤尾。

2007.04.02舊作肝劲,原發(fā)于CSDN blog http://blog.csdn.net/st_monad/article/details/1548862

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市郭宝,隨后出現的幾起案子辞槐,更是在濱河造成了極大的恐慌,老刑警劉巖粘室,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榄檬,死亡現場離奇詭異,居然都是意外死亡衔统,警方通過查閱死者的電腦和手機鹿榜,發(fā)現死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門海雪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人舱殿,你說我怎么就攤上這事奥裸。” “怎么了怀薛?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵刺彩,是天一觀的道長。 經常有香客問我枝恋,道長创倔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任焚碌,我火速辦了婚禮畦攘,結果婚禮上,老公的妹妹穿的比我還像新娘十电。我一直安慰自己知押,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布鹃骂。 她就那樣靜靜地躺著台盯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪畏线。 梳的紋絲不亂的頭發(fā)上静盅,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音寝殴,去河邊找鬼蒿叠。 笑死,一個胖子當著我的面吹牛蚣常,可吹牛的內容都是我干的市咽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抵蚊,長吁一口氣:“原來是場噩夢啊……” “哼施绎!你這毒婦竟也來了?” 一聲冷哼從身側響起贞绳,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谷醉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后熔酷,有當地人在樹林里發(fā)現了一具尸體孤紧,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡豺裆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年拒秘,在試婚紗的時候發(fā)現自己被綠了号显。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡躺酒,死狀恐怖押蚤,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情羹应,我是刑警寧澤揽碘,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站园匹,受9級特大地震影響雳刺,放射性物質發(fā)生泄漏。R本人自食惡果不足惜裸违,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一掖桦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧供汛,春花似錦枪汪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至趁舀,卻和暖如春赖捌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赫编。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工巡蘸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擂送。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓悦荒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嘹吨。 傳聞我的和親對象是個殘疾皇子搬味,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內容

  • 世界上有許多著名的貓:Kitty、加菲貓蟀拷、哆啦A夢碰纬、Tom……而科學界最著名的貓,大概就是“薛定諤的貓”了问芬。薛定諤...
    羅素的茶壺閱讀 25,763評論 73 685
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • ?編者按:針對于目前大量的靈修悦析,宗教以及商家,偷換量子理論的概念此衅,以達到其目的强戴,特轉發(fā)張?zhí)鞓s老師的科普系列文章《走...
    小義子_正版閱讀 1,315評論 2 5
  • 要認識神秘的量子糾纏亭螟,首先要認識神秘的量子現象。 不管是學哪個行業(yè)的骑歹,大概都聽說過奇妙的量子現象预烙。諸如測不準原理啦...
    josephok閱讀 1,856評論 1 16
  • 就在剛剛我的心理活動又泛濫了,我是個害羞的孩子自己心里又不承認覺得自己只是不屑于表達道媚,那句話練了不下二十遍扁掸,可...
    木子璐閱讀 223評論 0 0