12

Haskell での return の意味を理解したように見えたとき、さまざまな代替案を試してみましたが、return はモナド チェーンのどこでも使用できるだけでなく、完全に除外することもできるようです。

*Main> Just 9 >>= \y -> (Just y) >>= \x -> return x
Just 9

*Main> Just 9 >>= \y -> (return y) >>= \x -> (Just y)
Just 9

*Main> Just 9 >>= \y -> (Just y) >>= \x -> (Just x)
Just 9 

自分のインスタンスで return を省略しても、警告だけが表示されます...

data MaybeG a = NothingG | JustG a deriving Show 
instance Monad MaybeG where  
    --    return x = JustG x  
        NothingG >>= f = NothingG  
        JustG x >>= f  = f x  
        fail _ = NothingG  

Monad.hs:3:10:
    Warning: No explicit method nor default method for `return'
    In the instance declaration for `Monad MaybeG'

そして私はまだモナドを使うことができます

*Main> JustG 9 >>= \y -> (JustG 11) >>= \x -> (JustG y)
JustG 9

*Main> JustG 9 >>= \y -> (NothingG) >>= \x -> (JustG y)
NothingG

return キーワードの何がそんなに特別なのでしょうか? これは、省略できないより複雑なケースに関するものですか? それとも、別の方法で実行できる場合でも、これが「正しい」方法であるためですか?

更新: .. または別の代替手段として、独自のモナド値コンストラクターを定義できます

finallyMyLastStepG :: Int -> MaybeG Int
finallyMyLastStepG a = JustG a  

同じチェーンの別のバリアントを生成します(同じ結果になります)

*Main> JustG 9 >>= \y -> (JustG 11) >>= \x -> (finallyMyLastStepG y)
JustG 9
4

3 に答える 3

37

return キーワードの何がそんなに特別なのでしょうか?

まず、Haskell のキーワードでreturnはありません。オーバーロードされた関数です。

その型は次のように与えられます:

class  Monad m  where
    -- | Sequentially compose two actions, passing any value produced
    -- by the first as an argument to the second.
    (>>=)       :: m a -> (a -> m b) -> m b

    -- | Inject a value into the monadic type.
    return      :: a -> m a

これは、 type の値を指定すると、 typeの新しい値を返すreturn関数であることがわかります。ここで、 は のインスタンスである型です。そのようなタイプは次のとおりです。am amMonad

  • モナド[]
  • モナドI0
  • モナドMaybe
  • モナドSTM
  • モナド((->) r)
  • モナド(Either e)
  • モナド(ST s)

などなど。「Monad」のインスタンスは、次の法則を満たす必要があります。

> return a >>= k  ==  k a
> m >>= return  ==  m
> m >>= (\x -> k x >>= h)  ==  (m >>= k) >>= h

関数の実装はa -> m a簡単に推測できます。最も一般的なモナドの定義は次のとおりです。

リスト:

 return x = [x]

多分

 return x = Just x

returnこれは、値をモナド ラッパーに「持ち上げる」オーバーロードされた関数であることがわかります。したがって、その定義を使用できる場所ならどこでも使用できます。例えば

Prelude> 1 : return 2
[1,2]

または概念で(式を連鎖するときdo役立ちます)。

> do v <- return 7 ; return v :: Maybe Int
Just 7

モナドを使用する本当の理由returnは、いくつかのモナドで複数の値を合成するときです:

Prelude> do x <- return 1 ; y <- return 2 ; return (x + y) :: Maybe Int
Just 3
Prelude> do x <- Nothing  ; y <- return 2 ; return y
Nothing

最後のステートメントでは、指定されたモナドの値が 0 になるとチェーンがどのように短絡したかがわかります。この場合Nothing

概要:return値をモナド ラッパーに持ち上げるオーバーロードされた関数です。値を持ち上げる必要がある場合に使用します。命令型言語にあるような制御フロー キーワードではありません。

于 2013-03-10T16:34:08.567 に答える
13

Haskell のモナドのコンテキストで「リターン」が何を意味するのかを誤解していると思われます。return は、を受け取り、「ラップされた」もの、つまり可能な限り単純なモナドのインスタンスを返す関数です。他の言語では、しばしば と呼ばれます。C に似た言語で見られる「制御フロー」ではありません。aaUnitreturn

したがって、モナドの例では、を受け取り、を返すMaybe関数としてreturnが定義されています。aMaybe a

return :: a -> Maybe a

そして、それは何をしますか?あなたがそれを与えるならx、それはあなたを返しますJust x

return x = Just x

returnそして、その関数が必要なときに、書き出すのではなく、省略形として使用できるようになりました。

\x -> Just x

return表記法でモナドを書き出すdoと、C に似た言語で行うことのように見えるため、この名前が付けられています 。

于 2013-03-10T15:35:49.240 に答える
2

マイク・ハートルのコメントは私を正しい方向に導きましたが、それほど正式なものではありませんでした.

どの型クラスでも、それがサポートする演算子がリストされており、このクラス コンテキストでのみ機能する関数があります (クラス制約記号 => によって課せられます)。たとえば、filterM 署名

filterM :: Monad m => (a -> m Bool) -> [a] -> m [a] 

モナドのコンテキストでのみ使用できることを示しています。魔法は、この関数の本体では、クラスが持つ任意の演算子 (>>= と Monad の return) を自由に使用でき、インスタンス (たとえば my MaybeG ) にメソッド (私の場合は return) がない場合、関数は次のことができることです。不合格。だから、リターンがそこにあるとき

> filterM (\x -> JustG (x > 0)) [2, 1, 0, -1] 
JustG [2,1]

そしてそれがコメントされたとき(質問のMaybeGの私の実装を参照してください)

> filterM (\x -> JustG (x > 0)) [2, 1, 0, -1] 

*** Exception: Monad.hs:3:10-21: No instance nor default method for class operation GHC.Base.return

そのため、このクラス (この場合はモナド) 制約で動作する関数でインスタンスを使用する予定がある場合は、任意の演算子 (モナドの場合は return) の実装が必要です。

私の最初の誤解は、ほとんどのチュートリアルが多相 (アドホック) コンテキストなしでモナド チェーンを説明しているという事実によるものだと思います。私の意見では、このコンテキストにより、モナドはより強力で再利用可能になります。

于 2013-03-12T10:03:08.057 に答える