2017-01-24 33 views
3

在開始學習Haskell之後,即使在閱讀了大量文檔之後,Haskell仍然不明白。函數式編程:副作用實際發生在哪裏?

據我所知,要執行IO操作,您必須使用「IO monad」以「黑匣子」的形式包裝值,以便使用IO monad的任何函數仍然是純粹的功能。好吧,很好,但是IO操作實際發生在哪裏?

這是否意味着Monad本身不是純粹的功能?或者是IO操作實現了,比方說C語言,並且在Haskell編譯器中「嵌入」?

我可以在純Haskell中編寫帶有或不帶Monad的東西,它可以執行IO操作嗎?如果不是,如果語言本身不可能,這種能力從何而來?如果它在Haskell編譯器內嵌入/鏈接到C代碼塊,IO Monad是否最終會調用它來執行「髒作業」?

+1

(評論,因爲我不是100%確定這一點)我的理解是,IO被模擬爲一個低級別的狀態monad與「現實世界」作爲國家。編譯器/運行庫實際上將其轉換爲使用綁定到操作系統的API實現的IO操作。一個純粹的函數式編程能夠計算出任何東西,但不會告訴任何人。我們需要一個運行時,可以將現實世界中的這些有狀態操作轉換爲對底層操作系統的實際調用。 – bheklilr

+0

https://wiki.haskell.org/IO_inside#Welcome_to_the_RealWorld.2C_baby –

回答

17

作爲一篇序言,它不是「IOMonad」,儘管很多寫得不好的介紹說。這只是「IO類型」。單子沒有什麼神奇的。 Haskell的Monad類是一個非常無聊的事情 - 它只是大多數語言可以支持的不熟悉和抽象。你永遠不會看到任何人打電話IOIOAlternative」,即使IO實施Alternative。專注於Monad只會妨礙學習。

在純語言中原則上處理效果(而不是副作用!)的概念魔術根本就存在IO類型。這是一個真正的類型。這不是一個國旗說「這是不純的!」。它是一個完整的Haskell類型* -> *,就像Maybe[]一樣。將類型簽名接受IO值作爲參數,如IO a -> IO (Maybe a),這是合理的。使用嵌套的IO輸入簽名很有意義,如IO (IO a)

所以如果它是一個真正的類型,它必須有一個具體的含義。作爲類型的Maybe a表示類型a的可能缺失值。 [a]表示類型爲a的0個或更多值。 IO a表示產生a類型值的一系列效果。

請注意,IO的整個目的是表示一系列效果。正如我上面所說,他們不是副作用。它們不能隱藏在程序的無傷大雅的葉子中,神祕地改變其他代碼背後的東西。相反,由於它們是IO值,所以效果被明確地調出。這就是爲什麼人們試圖使用IO類型來最小化他們的程序的一部分。你在那裏做的越少,在遠處干擾你的程序的怪異行爲的方式越少。

至於你的問題的主要推力,那麼 - 一個完整的Haskell程序是一個IO的值,main,以及它使用的定義集合。編譯器在生成代碼時,插入一個確實非Haskell代碼塊,該代碼塊實際運行IO值中的效果序列。從某種意義上說,這就是Simon Peyton Jones(GHC的長期作者之一)在他的演講Haskell is useless中所做的。

的確,無論實際執行IO操作如何,都不能保持概念上的純粹。(這裏有一個非常不純的函數,運行在Haskell語言中暴露的動作IO。我不會再多說它,它會被添加來支持外部函數接口,並且不恰當地使用它會使程序非常糟糕。)但是Haskell的重點是爲效果系統提供一個原則性的接口,並隱藏無原則的位。而且它在實踐中確實非常有用。