2012-03-15 48 views
8

我經常發現自己希望將常規函數插入「綁定」序列中。像這種人爲的例子:測序與純函數結合

getLine >>= lift (map toUpper) >>= putStrLn 

我需要定義提升功能lift :: (a -> b) -> a -> m b,使這項工作。問題是我不知道這樣的功能,並且Hoogle似乎也沒有。我覺得這很奇怪,因爲這對我來說完全有意義。

現在,可能還有其他方法可以使這項工作成爲可能,但我喜歡無點式樣式代碼的方式,讓我可以一遍掃描一行來找出正在發生的事情。

let lift f x = return (f x) in 
getLine >>= lift (map toUpper) >>= putStrLn 

我的問題歸結爲:我是否錯過了某些東西或者沒有像升降機這樣的功能。我在Haskell的經驗仍然非常有限,所以我認爲大多數人以不同的方式解決這個問題。有人能向我解釋解決這個問題的慣用方法嗎?

回答

18

有三種慣用的方式。

  1. 不要使用綁定;使用您Hoogle搜索先打來代替:

    liftM (map toUpper) getLine >>= putStrLn 
    

    有各種各樣的liftM替代拼寫,如fmap(<$>)

  2. 內嵌您定義的lift功能:

    getLine >>= return . map toUpper >>= putStrLn 
    
  3. 使用單子法律融合的最後兩個結合在選項2:

    getLine >>= putStrLn . map toUpper 
    
+1

我會把'FOO >> =返回。 bar >> = baz'最後在列表中。在較長的連鎖店中,這很好,但在例如'foo >> = baz的例子中。酒吧'是更可讀的國際海事組織。 – 2012-03-15 13:03:34

+0

其實我覺得'foo >> = return。 bar >> = baz'是一個整潔的方式。我並沒有想到,這實際上是我尋找的提升功能。 – 2012-03-15 13:28:23

+4

'putStrLn。 map toUpper = << getLine'看起來很整齊。我喜歡使用'= <<',因爲它類似於函數應用程序。 – danr 2012-03-15 14:00:28

3

在這種情況下使用Functor實例:

> import Data.Char 
> import Data.Functor 
> map toUpper <$> getLine >>= putStrLn 
foo 
FOO 
>