2014-12-11 64 views
4

Typeclassopedia提出這個練習:實現`單子(( - >)E)`

Implement a Monad instance for ((->) e).

這裏的MyMonad類。

class (MyMonad m) where 
    ret  :: a -> m a 
    flatMap :: m a -> (a -> m b) -> m b 

然後,我開始試圖爲((->) e)實現Monad實例。

instance (MyMonad (-> e)) where 
    ret x  = ... 
    flatMap m f = ... 

但是,我沒有直覺((->) e)的含義。

請幫我理解它,並給我一個解決ret的提示。

+1

首先,你需要了解參數類型:所以如果我寫'data Foo x = ...'我有一個類型的家族,我們可以稱之爲「抽象類型」Foo。 (官方的描述是'Foo'是一種類型'* - > *',所以放入任何類型的'*'都會給出一種'*'類型)。如果你明白這一點,那麼'( - >)a'是一種類型'* - > *',就像'Foo'是我們指定數據Foo x = ...'時一樣。它是以「a」作爲參數的抽象類型的函數。 – 2014-12-11 15:57:38

回答

6

這裏有一些語法技巧。它可能會更容易想到的(->) e(e ->)或者更明確地,如果我們寫

type Arr a b = a -> b 

然後(->) e是大致相同。

那麼ret的類型是什麼?它結束爲

ret :: a -> (e -> a) 

現在應該更容易解決。

+0

這是'( - > e)'的GHC vesrion嗎? '前奏>讓f =返回(+ 10)||| Prelude>(return 10)>> =(\ x - > fmap($ x)f)=== 20' – 2015-04-03 17:28:50

+0

該代碼段中有很多內容。我不知道你在問什麼,我想。 – 2015-04-03 17:58:40

+0

我在問我的兩行代碼是否證明了'( - >)e' Monad的預期行爲 - 根據我上面提到的問題回答。 – 2015-04-03 18:11:45

5

如果Haskell允許類型操作符 部分IMO,這將更容易理解。該類型

a -> b 

是相當於

(->) a b 

這樣就意味着

(->) a 

相同

(a ->) 

它本質上說,它的功能類型參數通過其 輸出類型。因此,這意味着,我們應該有

ret :: a -> (((->) r) a) 

或等價

ret :: a -> ((r ->) a)  -- Note that this is invalid Haskell, it's using our magical TypeOperatorSections extension 
ret :: a -> (r -> a) 
ret :: a -> r -> a 

警告:破壞者AHEAD!

嗯,這種類型看起來很簡單和熟悉。如果我們看看它在Hoogle,在 第一個結果是

const :: a -> b -> a 

和結果的其餘約seqpar,以及其他更先進的功能 ,我們可以相當肯定都不是我們」重新尋找。所以 const是:

instance MyMonad ((->) r) where 
    return = const 

對於flatMap實施,我們可以通過註釋我們的論點 與它們的類型入手:

flatMap (m :: r -> a) (f :: a -> (r -> b)) = _ 

所以我們有一個功能,當給定r回報a,以及 給定的功能ar返回b,並且我們想要flatMap m f :: r -> b。由於我們 有r類型沒有參數,下面我們來介紹一個:

flatMap m f = \r -> _ 

如果你使用的輸入孔,GHC會告訴你,現在你需要b 類型的東西。相關的綁定是

m :: r -> a 
f :: a -> r -> b 
r :: r 

只有一種方式來獲得a,這是從m,所以

flatMap m f = \r -> _ (m r) 

現在我們已經GHC告訴我們,我們需要a -> b類型的東西,與相關 綁定

f :: a -> r -> b 
r :: r 

這看起來非常簡單的對我說:

flatMap m f = \r -> f (m r) r 

而我們的代碼類型檢查!現在有時間來測試它。期望的行爲是 我們相同的輸入參數傳遞給幾個功能在DO塊(你 可以使用RebindableSyntax 如果你真的想用做記號),所以像

test :: Int -> Int 
test = 
    (*2) `flatMap` (\x1 -> 
     (^3) `flatMap` (\x2 -> 
      (7-) `flatMap` (\x3 -> 
       return (x1 * x2 + x3) 
      ) 
     ) 
    ) 

應該是相同的作爲

test' x = (2*x) * (x^3) + (7-x) 

而對於我們的實現,它確實工作:

> test 5 == test' 5 
True 
> test 100 == test' 100 
True 
+0

感謝您的深入解答。我怎樣才能創建一個MyMonad的實例?我嘗試了以下失敗:'ret(+ 10):: MyMonad(( - >)Int)'錯誤:'期望的類型,但是MyMonad(( - >)Int)'有種'Constraint'' – 2015-04-05 02:02:30

+1

@KevinMeredith我不確定我是否完全跟隨你。 'MyMonad'是一個類型類,所以如果你想創建它的一個實例,你可以使用'instance MyMonad SomeType where ret = ...; flatMap = ...'。由於'MyMonad'是一個類型類型,你可以將它用作一個約束('=>'左邊的位),就像'MyMonad m => m()'一樣。在這種情況下,我認爲你實際上需要'ret(+ 10):: MyMonad m => m(Int - > Int)'。 '(( - >)Int')類型需要另一個參數來表明它實際上是一個函數。 – bheklilr 2015-04-05 02:16:13

+1

@KevinMeredith如果你想讓'( - >)Int'成爲'MyMonad m => m''中的'm',這在Haskell中並不合理。你不會寫'return():: Monad IO => IO()',你只需要寫'return():: IO()'。 – bheklilr 2015-04-05 02:17:13

相關問題