2010-07-16 38 views
1

如果我這樣定義「綁定」功能:單子「綁定」功能的問題

(>>=) :: M a -> (a -> M' b) -> M' b 

將這個定義幫助我,如果我想要的結果是一個新的單子類型,或者我應該使用相同的Monad但與之前的b在相同的Monad框中?

+1

如果是這樣,那麼'M'和'M''不是(只)單子。 – kennytm 2010-07-16 18:36:44

+0

...以及爲什麼要將一個monad轉換爲另一個monad?例如,我認爲將IO轉換爲Maybe可能不安全。雖然可以組成monad('IO(也許a)')。 – kennytm 2010-07-16 18:48:41

+0

轉換爲不同的Monad,以便直觀地進行更多不同的計算。但也許這沒有用,對吧?我正在尋找例子來證明有這樣的理由。 – Rn2dy 2010-07-16 18:53:33

回答

7

正如我在評論中提到的,我不認爲這樣的操作可以安全地定義爲一般單子(例如M = IOM' = Maybe)。

然而,如果M是安全地轉換爲M」,則此綁定可被定義爲:

convert :: M1 a -> M2 a 
... 

(>>=*) :: M1 a -> (a -> M2 b) -> M2 b 
x >>=* f = convert x >>= f 

反之,

convert x = x >>=* return 

一些這樣的安全轉換方法是maybeToList(也許→ []),listToMaybe([] →也許),stToIO(ST RealWorld → IO),...請注意,對於任何monads,沒有通用的convert方法。

+0

除身份。 – luqui 2010-07-16 22:40:59

1

這個定義不僅沒有幫助,而且會嚴重混淆未來的代碼讀者,因爲它會打破所有使用它的期望。

例如,M和M'是否應該是Monads?如果是這樣,那麼他們是如何定義的?請記住:>>=的定義是Monad定義的一部分,並且在任何地方用於定義其他Monad使用函數 - 除returnfail本身之外的每個函數。

另外,您是否選擇使用哪個M和M,還是計算機?如果是這樣,那麼你如何選擇?它是否適用於任何兩個Monad實例,或者是否存在您想要的Monad子集 - 或者M的選擇決定了M'的選擇?

這有可能使像你寫的功能,但它肯定是一個很多>>=更加複雜,而且會產生誤導,殘酷的,可能是災難性的,試圖填滿你的函數爲>>=「穿衣服。

1

這可能是做一個複雜的事情,但它在某些情況下是可行的。基本上,如果他們是可以在裏面看到的monads(例如Maybe或您寫的monad),那麼您可以定義這樣的操作。

有時候很方便(在GHC中)有一件事是用你自己的一個替換Monad類。如果你定義了return, >>=, fail,你仍然可以使用do表示法。這裏有可能會像你想要的一個例子:

class Compose s t where 
    type Comp s t 

class Monad m where 
    return :: a -> m s a 
    fail :: String -> m a 
    (>>=) :: (Compose s t) => m s a -> (a -> m t b) -> m (Comp s t) b 
    (>>) :: (Compose s t) => m s a -> m t b -> m (Comp s t) b 
    m >> m' = m >>= \_ -> m' 

然後,您可以控制哪些類型可以使用基於您定義的Compose哪些實例在綁定運營商進行測序。當然,你經常需要Comp s s = s,但你也可以用它來定義各種瘋狂的東西。例如,你可能在你的monad中有一些操作,絕對不能跟隨任何其他操作。想要執行這個靜態?定義一個空數據類型data Terminal並且不提供Compose Terminal t的實例。

此方法不適用於從(比如說)Maybe轉換爲IO,但它可用於攜帶有關您所做的某些類型級別的數據。

如果你確實想改變單子,你可以修改類定義上述弄成

class Compose m n where 
    type Comp m n 
    (>>=*) :: m a -> (a -> n b) -> (Compose m n) b 

class Monad m where 
    return :: a -> m a 
    fail :: String -> m a 
    (>>=) :: Compose m n => m a -> (a -> n b) -> (Compose m n) b 
    m >>= f = m >>=* f 
    (>>) :: Compose m n => m a -> (n b) -> (Compose m n) b 
    m >> n = m >>=* \_ -> n 

我用前者風格善始善終,但我想,後者的想法也可能在某些情況下有用。