2011-10-20 12 views
7
は、次のように

私はモナドのインスタンスを定義しています:Haskellはいつ呼び出すべき「返品」を知っていますか?

data Something = Something a 

instance Monad Something where 
    return a = Something a  --Wraps a in 'Something', correct? 
    m >>= f = do 
     var <- m 
     return $ f var   --I want this to pass var to f, then wrap the result 
            --back up in the 'Something' monad with the return I 
            --Just defined 

質問がある - >

1:私がやっているものとの任意の明白なエラー/誤解がありますか?

2:私はいくつかの理由で、私はモナドで定義された別の関数

f :: Something a -> Something b 
f x = do 
    var <- x 
    return $ doMagicTo x 

ウィルreturnコールのリターンを定義する場合:Haskellは私がm >>= f

3から上記で定義されているリターンを呼び出すために知っているだろうインスタンスとラップx Somethingに?

答えて

15

ここには大きな問題がいくつかあります。

まず、Monadインスタンスはkind* -> *である必要があります。つまり、少なくとも1つの型変数が必要です。Somethingには変数がありません。比較のために:

-- kind * -> * 
Maybe 
IO 
Either String 

-- kind * 
Maybe Int 
IO() 
Either String Double 

は、あなたがそれらを使用する前にMaybeIO、およびEither Stringの各タイプのパラメータを必要とする方法を参照してください?あなたがあなたの定義を変更する必要があるのでSomethingで、記入するタイプのパラメータのための場所がありません:。

data Something a = Something a 

第二の大きな問題は、あなたのモナドのインスタンス内>>=が間違っているということです。あなたは一般的に関数return>>=を呼び出すだけなので、表記法を使うことはできません。だから、あなたはモンドの機能なしに書かなければなりません。表記か、>>=またはreturnを呼び出す必要があります。

instance Monad Something where 
    return a = Something a  --Wraps a in 'Something' 
    (Something m) >>= f = f m  --unwraps m and applies it to f 

>>=の定義は、あなたが予想よりも簡単です。解凍mは、Somethingコンストラクタでパターンマッチングする必要があるため、簡単です。またf :: a -> m bだから、fがあなたのためにそれを再度ラップすることを心配する必要はありません。

一般でモナドをアンラップする方法はありませんが、非常に多くの特定モナドをアンラップすることができます。

do-notationや、>>=を使用して構文的に間違っていることはないことに注意してください。問題は、>>=が再帰的に定義されているため、プログラムを使用しようとすると無限ループになります。

(ここで定義されているようN.B. SomethingIdentity monadある)

あなたの3番目の質問については、モナドのインスタンスで定義されているそうreturn関数が呼び出されるものです。型クラスは型によって送出されます。指定した型はSomething bでなければなりません。コンパイラはSomethingのMonadインスタンスを自動的に使用します。 (私は最後の行がdoMagicTo varであることを意味したと思います)。

+3

これは素晴らしいことです。これらの答えはすべてとても良いです。私は、これまでのところハスケルコミュニティが、私が遭遇したことの中で最も有用で徹底的であったことを強く主張します。乾杯。 – providence

2
  1. 閉じる。 returnはここでは冗長なので、型コンストラクタをSomething型コンストラクタに追加する必要があります。 編集:このコードはまだ間違っています。 >>=の定義は円形です。詳細については、他の回答を参照してください。

    data Something a = Something a 
    
    instance Monad Something where 
        return a = Something a 
        m >>= f = do 
         var <- m 
         f var 
    
  2. >>=のためのあなたの定義はinstance Monad Something where下にあるので、>>=のタイプはSomething a -> (a -> Something b) -> Something bです。したがって、f varSomething bである必要があります。ここにGoogleへの言葉は "タイプ推論"

  3. はいです。この場合も、これは型推論です。コンパイラがあなたが望むタイプを推論できないなら、あなたにそれを伝えます。しかし、通常それができます。

+0

John Lの解決法を参照してください。doブロックを使用して、 'do = block 'を定義することはできません。 (また、放浪の解決策に記載されています。) – ivanm

+0

D'oh、よかったです。私はOPのコードを取り出し、タイプチェックしてコンパイルして、 "うん、それは正しいだろう"と言い張るまで修正したので、私は今ハスケルのプログラマーのように思っていなければなりません。 :Pでも、私はOPの質問は多かれ少なかれだと思います。「ハスケルは型推論をしますか?彼らはそのように尋ねなかったが。そして私の主なポイントは、そうです。 – MatrixFrog

7

主な問題は、>>=の定義が円形であることです。だから、あなたが円形である、m >>= \...としてm >>= fを定義している

m >>= f = 
    m >>= \var -> 
    return $ f var 

m >>= f = do 
    var <- m 
    return $ f var   

Desugarsあなたの定義がよう

Haskellの構文を行うには、>>=>>のチェーンのための糖衣構文です。

>>=で行う必要があるのは、mから値を抽出してfに渡す方法を定義することです。さらに、fはモナドの値を返す必要があるので、ここでreturnを使用すると間違っています(これはfmapを定義する方法に近い)。

Somethingため>>=の定義は次のようになります。

(Something a) >>= f = f a 

これはアイデンティティモナドである - それについて書かれた良い取引があります - それはモナドがどのように働くか理解するための良い出発点です。

関連する問題