6

次のamazinコードを書いたとしましょう。

func = do
  a <- Just 5
  return a

それはかなり無意味です、私は知っています。ここで、aは、、5func返しますJust 5

今、私は私の素晴らしい(まだ無意味な)関数を書き直します:

func' = do
  a <- Nothing
  return a

この関数はを返しますNothingが、一体何aですか?値から抽出するものは何もありNothingませんが、次のようなことをしてもプログラムは泣き言を言いません。

func'' = do
  a <- Nothing
  b <- Just 5
  return $ a+b

私は実際に何が起こっているのかを見るのに苦労しています。何aですか?言い換えれば、<- 実際には何をしているのでしょうか。「右側から値を抽出して左側にバインドする」と言うのは、明らかに過度に単純化されています。何が得られないのですか?

ありがとう :)

4

5 に答える 5

11

その最後の例の表記法を脱糖してみましょう。

func'' = Nothing >>= (\a -> Just 5 >>= (\b -> return $ a+b))

それでは、多分>>=がどのように定義されているか見てみましょう。それは前奏曲にあります:

instance  Monad Maybe  where
    (Just x) >>= k   =  k x
    Nothing  >>= k   =  Nothing
    return           =  Just
    fail s           =  Nothing

だからNothing >>= foo単にNothing

于 2012-04-18T07:49:06.460 に答える
6

答えは、次のMonadインスタンスの定義にありますMaybe

instance Monad Maybe where
   (Just x) >>= k      = k x
   Nothing  >>= _      = Nothing
   (Just _) >>  k      = k
   Nothing  >>  _      = Nothing
   return              = Just

あなたのfunc''翻訳:

Nothing >>= (\a -> (Just 5 >>= (\b -> return (a+b))))

の定義から、最初のものが結果にスレッド化されている(>>=)ことがわかります。Nothing

于 2012-04-18T07:55:23.880 に答える
5

Maybeモナドの定義を見てみましょう。

instance Monad Maybe where
  return = Just

  Just a  >>= f = f a
  Nothing >>= _ = Nothing

そしてdo、関数の-notationを脱糖します。

func' =
  Nothing >>= \a ->
  return a

の最初の引数>>=はであり、上記の定義から、2番目の引数を無視してNothingいることがわかります。>>=したがって、次のようになります。

func' = Nothing

関数\a -> ...が呼び出されるaことはないため、割り当てられることはありません。したがって、答えは次のとおりaです。到達すらされていません。


do糖-表記については、これがどのように行われるかについての簡単なスケッチです(私が行った1つの簡略化-処理fail、つまり一致しないパターン):

do {a; rest} → a >> do rest

これ>>は通常、>>=asの観点から実装されることに注意してくださいa >>= \_ -> do rest(つまり、2番目の関数は引数を無視するだけです)。

do {p <- a; rest} → a >>= \p -> do rest

do {let x = a; rest} → let x = a in do rest

そして最後に:

do {a} = a

次に例を示します。

main = do
  name <- getLine
  let msg = "Hello " ++ name
  putStrLn msg
  putStrLn "Good bye!"

脱糖剤:

main =
  getLine >>= \name ->
  let msg = "Hello " ++ name in
  putStrLn msg >>
  putStrLn "Good bye!"

そして、好奇心旺盛な人のためにそれを完成させるために、ここにdo {p <- a; rest}(Haskellレポートから直接取られた)の「正しい」翻訳があります:

do {pattern <- a; rest} → let ok pattern = do rest
                              ok _       = fail "error message"
                          in  a >>= ok
于 2012-04-18T07:50:32.713 に答える
2

Nothing実際には「何もない」というわけではなく、実際にはMaybeモナド内の何かの可能な値です。

data Maybe t = Nothing | Just t

つまり、あるタイプのタイプMaybe tの何かがある場合t、それは値Just xxタイプの何かがどこにあるかtまたは Nothing;を持つことができます。この意味では、もう1つの可能な値を持つようMaybeに拡張されます。(モナドであるため、他のプロパティがありますが、との構文糖衣を除いて、ここでは実際には関係ありません。)tNothingdo<-

于 2012-04-18T07:57:06.923 に答える
1

あなたの例を見てみましょう:

func = do
  a <- Just 5
  return a

他のプログラミング言語と同じように、これを「これまでに行われたこと」と「まだ行われていないこと」に対応する2つの部分に分割できます。たとえば、との間Just 5で休憩をとることができます

a <- ...
return a

多くの一般的なプログラミング言語ではJust 5、が変数に詰め込まれa、コードが続行されることを期待しています。

Haskellは何か違うことをします。a「コードの残りの部分」は、それに入れる価値がある場合に何をするかを説明する関数と考えることができます。次に、この関数はに適用されJust 5ます。ただし、直接適用されるわけではありません。>>=式のタイプに応じて、適用される定義を使用して適用されます。の場合Maybe、を処理するときに「残りのコード」関数がに適用さ>>=れるように定義されます。ただし、「コードの残りの部分」を処理するときに関数が単に無視されて返されるようにも定義されています。Just XXNothingNothing

これで、他の例を解釈できます

func'' = do
  a <- Nothing
  b <- Just 5
  return $ a+b

に分割Nothingして:

  a <- ...
  b <- Just 5
  return $ a+b

上で述べたように、このコードブロックは、の可能な値に適用される関数と考えることができますa。しかし、これはで使用されてNothingおり、この場合>>=、「残りのコード」を無視して、を返すように定義されていますNothing。そして、それはあなたが得た結果です。

于 2012-04-19T01:51:52.457 に答える