2017-09-24 40 views
2

我知道我可以使用函數單子來實現類似下面的一個結構(在這裏我重複使用多次調用的參數不明確引用它)之前執行轉換到輸入:應用功能單子

compute_v0 :: String -> String 
compute_v0 = do 
    x <- length -- (using the argument implicitly here) 
    top <- head -- (and here) 
    return (replicate x top) 

對上述函數的結果:compute "1234""1111"

我的問題是:我將如何執行做塊之前應用轉換到「隱藏」的說法(想象一下,我想追加「ABCD 「到列表中)。

我的第一個解決方案:

compute_v1 :: String -> String 
compute_v1 = compute_v1' . (++ "abcd") 

compute_v1' ::String -> String 
compute_v1' = do 
    x <- length 
    top <- head 
    return (replicate x top) 

compute "1234"結果現在是"11111111"。這實際上完成了這項工作,但我寧願將它全部定義在一個簡潔的代碼塊中。

我能得到的最接近實際包括同時仍保持與代碼(V0)的風格改造這一項:

compute_v2 :: String -> String 
compute_v2 = (++ "abcd") >>= \r -> do 
    let x = length r 
    let top = head r 
    return $ replicate x top 

但我還是必須包括一個拉姆達,使用了大量的let綁定的並明確引用lambda參數。有更好的方法來實現這樣的結構嗎?

+0

'compute_v1 = liftA2重複長度頭。 (++「abcd」)' – 4castle

+0

'compute_v1 =(複製<$>長度<*>頭)。 (++「abcd」)' – Redu

回答

5

由於所有Monad情況下,也有Functor實例和Functor功能實例有fmap = (.),你可以有

compute :: String -> String 
compute = flip fmap (++ "abcd") $ do 
    x <- length 
    top <- head 
    return $ replicate x top 

有些軟件包(如microlenslens)定義(<&>) = flip fmap,讓你寫

compute :: String -> String 
compute = (++ "abcd") <&> do 
    x <- length 
    top <- head 
    return $ replicate x top 

(->)也有一個Category實例,其中giv es我們(>>>) = flip (.)。這可能會稍微更清晰,視覺:

compute :: String -> String 
compute = (++ "abcd") >>> do 
    x <- length 
    top <- head 
    return $ replicate x top 
+0

我僞裝成'(。)'時不會使用'fmap'。我會使用'flip(。)(++「abcd」)'或'(。(++「abcd」))''。(嗯,說實話,我絕對不會寫這個monadic風格,但OP似乎想要試驗這個) – chi

+0

@chi這是一個很好的觀點,但我想突出思考過程有點讓我想起它(這是因爲我們正在使用它的monadic屬性,請嘗試查看'Functor'實例的功能)。 –

+0

我明白了。是的,我同意這個過程。 – chi

4

你可以做這樣的事情:

compute_v2 :: String -> String 
compute_v2 = do 
    x <- length 
    top <- head 
    return $ replicate x top 
    <$> (++ "abcd") 

據我所知,有問題的單子被稱爲讀者單子,並且它也是一個Functor

*Q46393211> compute_v2 "1234" 
"11111111" 
*Q46393211> compute_v2 "71" 
"777777" 
+1

@chi GHCi中加載的模塊中的代碼沒有解析錯誤。我還沒有嘗試'真正'編譯它... –

+0

我喜歡這些「簡單」的Haskell問題和答案,他們總是讓我的腦袋迅速旋轉。我目前對此有所瞭解:'<$>'是'fmap'的中綴運算符(查找[here](https://stackoverflow.com/questions/37286376/what-does-mean-in-haskell))。左邊的任何東西都是一個函數'a-> b',右邊是'f a'。所以這是一個函數?對於'do'塊本身,這是'List' monad,因爲字符串是字符列表? –

+0

@StefanHanke不,它一直是函數monad(和函數函子)。 「<-'s右邊的表達式的類型是函數類型,這是您可以判斷它是使用的函數monad實例的一種方式。解析在這裏有點奇怪(在我看來),但它似乎解析爲'compute_vs =(do {... do block code here ...})<$>(++「abcd」)'。如果我有這樣的事情,我會親自把這些包裹放在明確的位置。 –

1

MonadReader class有這種情況的方法local(->) r是一個實例,因此

import Control.Monad.Reader (local) 

compute_v3 ::String -> String 
compute_v3 = local (++ "abcd") $ do 
    x <- length 
    top <- head 
    return (replicate x top) 

應該工作(不能在此刻測試)。