2016-08-24 38 views
1

目標:有一個字符串並打印同樣的事情在控制檯一樣需要同樣的行動,永遠理解永遠在Haskell

做我想出了這樣的事情,沒有編譯錯誤,但工作不正常。

greet_buggy :: String -> IO() 
greet_buggy = forever $ putStrLn 

問題在於字符串不在控制檯中打印任何內容。

greet_buggy "something" 

基於this post我試圖調試和改變像下面的定義。它工作正常

greet :: IO() 
greet = forever $ putStrLn "Hello" 

任何人都可以解釋這是怎麼回事嗎?單獨使用forever可以達到相同效果嗎?

編輯:發現一個更多的相關post(感謝@丹尼爾瓦格納),即使通過這個問題是從我的不同,答案解釋約forever

+1

嘗試'greet_buggy =永遠。 putStrLn' – user2297560

+0

感謝,像迎接工作,但它仍然不是我的目標的完整解決方案?我想接受字符串並打印它,並接受一個像這樣的字符串永遠 –

回答

8

greet_buggy正在工作不同的月河畔。

forever需要一次性動作並無限期地重複它。它可以被定義如下:

forever a = let loop = a >> loop in loop 

這也可以看作

forever a = a >> a >> a >> a >> ... (infinitely many times) 

(實際上永遠是在應用型,沒有單子定義;但現在,這並不重要)。

所以forever greet實際上是

putStrLn "Hello" >> putStrLn "Hello" >> putStrLn "Hello" >> ... 

其不需要進一步解釋。

OTOH forever greet_buggy相當於

putStrLn >> putStrLn >> putStrLn >> ... 

現在,由於(-> a)是一個單子,>>是合適類型的任意兩個函數定義,以及f >> g在這種情況下,意思是...只是g!所以

(putStrLn >> putStrLn >> putStrLn >> ...) "Hello" 

的意思就是要把最後一個函數在>>鏈並將其應用到Hello。當然,這裏沒有最後一個功能,所以這只是永遠運行。

4

任何人都可以解釋這是怎麼回事嗎?

我們有

putStrLn :: String -> IO() 

,順便說一下,在(->) String單子的值。因此,

forever putStrLn :: (->) String b 

其中b普遍定量,因此我們也有(不幸)

forever putStrLn :: (->) String (IO()) 

使得貼出代碼類型檢查。

要了解什麼是forever(->) String單子,記得:

m >>= g 
= -- definition of >>= 
\x -> g (m x) x 

因此

m >> f 
= -- definition of >> in terms of >>= 
m >>= const f 
= -- definition of >>= 
\x -> const f (m x) x 
= -- beta 
\x -> f x 
= -- eta 
f 

返回forever:召回其定義

forever m = m >> forever m 

這相當於(在(->) String monad)遞歸定義

forever m = forever m 

導致無用的無限循環。

+0

所以'永遠$ putStrLn''東西「'總是會打印相同的IO動作,即打印某些東西,以防我想將」某物「改變爲」任何東西「我可以用'永遠'來做這件事嗎? –

+0

我不確定我是否理解:您可能正在尋找像'forever(do s < - getLine; putStrLn s)' – chi

+0

是的,您的解釋和此評論解決了我的問題。謝謝 –

2

forever一遍又一遍地執行完全相同的IO操作(或一般來說,monadic操作)。如果您的函數接受字符串作爲輸入,forever將永遠打印相同的字符串。相反,如果您想每次都從用戶那裏讀取一個字符串,則必須將其包含在IO操作中。

什麼是簡單的IO操作,從用戶讀取一行並打印出來?結合在了一起getLineputStrLn

echo :: IO() 
echo = getLine >>= putStrLn 

然後,只需傳遞行動forever

cat :: IO() 
cat = forever echo 

另外,原來已經有內置前奏的東西做這件事對你:我們已經寫成相當於:

cat :: IO() 
cat = interact id