2014-12-19 47 views
1

在頁面http://en.wikibooks.org/wiki/Haskell/do_Notation上,有一種非常方便的方法來將do語法綁定到函數形式(我的意思是使用>> =)。它非常適用不少情況下,直到我遇到了一段代碼,涉及職能單子(( - >)R)將語法轉換爲>> = with(( - >)r)monad

的代碼是

addStuff :: Int -> Int 
addStuff = do 
    a <- (*2) 
    b <- (+10) 
    return (a+b) 

這相當於爲定義

addStuff = \x -> x*2+(x+10) 

現在,如果我用方便的方法重寫做兼職,我得到

addStuff = (*2) >>= \a -> 
      (+10) >>= \b -> 
      a + b 

這給編譯埃羅河我知道a,b是Int(或其他類型的Num),所以最後一個函數(\ b - > a + b)的類型是Int - > Int,而不是Int - > Int - > Int。

但是,這是否意味着並不總是有一種方法可以從do轉換爲>> =?有沒有解決這個問題?或者我只是不正確地使用規則?

回答

3

問題做出最後的單子:

addStuff = (*2) >>= \a -> 
      (+10) >>= \b -> 
      return (a + b) 
+1

我看到這個作品。但重點可能不是格式,而是將Int包裹到(Int - > Int)的返回值。不管怎麼說,還是要謝謝你! – 2014-12-19 06:16:38

+0

是的,你是對的。也感謝你。 – 2014-12-19 06:24:06

1

(你已經有了答案,那)正確的表達必須在最後一行用return

addStuff = (*2) >>= \a -> 
      (+10) >>= \b -> 
      return (a + b) 

(對此進行闡述,作一些澄清)return是monad定義的一部分,而不是do表示法。

代的實際定義爲((->) r)單子,就相當於

addStuff x 
    = ((\a -> (\b -> return (a + b)) =<< (+10)) =<< (*2)) x 
    = (\a -> (\b -> return (a + b)) =<< (+10)) (x*2) x 
    = ((\b -> return ((x*2) + b)) =<< (+10)) x 
    = (\b -> return ((x*2) + b)) (x+10) x 
    = return ((x*2) + (x+10)) x 
    = const ((x*2) + (x+10)) x 
    =   (x*2) + (x+10) 

預期。因此,在一般情況下,功能,

do { a <- f ; b <- g ; ... ; n <- h ; return r a b ... n } 

相同

\ x -> let a = f x in let b = g x in ... let n = h x in r a b ... n 

(不同之處在於每個標識符a,b,...,n不應該出現在相應的函數調用,因爲let綁定是遞歸的,和do綁定都沒有)。

上面的do代碼也正是liftM2在Control中的定義。單子:

> liftM2 (+) (*2) (+10) 100 
310 

liftM_N任何N可以通過使用的liftMap進行編碼:

> (\a b c -> a+b+c) `liftM` (*2) `ap` (+10) `ap` (+1000) $ 100 
1410 

liftMfmap的一元當量,這對於功能是(.),所以

(+) `liftM` (*2) `ap` (+10) $ x 
    = (+) . (*2) `ap` (+10) $ x 
    = ((+) . (*2)) x ((+10) x) 
    = (x*2) + (x+10) 

因爲ap f g x = f x (g x) for functions(aka S -combinator)。

+0

謝謝!這是很多有用的信息。 – 2014-12-20 18:52:00

相關問題