11

関数モナドと少し混乱しています。関数モナドは次のように定義されています。

instance Monad ((->) r) where
     return x = \_ -> x
     h >>= f = \w -> f (h w) w

バインディング操作を記述して、それを試してみました。

( (*2) >>= (+10) ) 3 

(return 3) :: ((->) Int)

しかし、それはエラーを引き起こしました。また、関数AddStuffをバインディング操作に書き直そうとしています。

addStuff = do
           a <- (*2)
           b <- (+10)
           return (a+b)

次に、この関数をに変換します

addStuff' w = (*2)  w >>= (\a ->
              (+10) w >>= (\b ->
              return (a+b) ))

新しい関数のタイプを確認します。

addStuff :: (Monad m, Num (m b), Num b) => m b -> m b 

何故ですか?どうすれば修正できますか?

4

1 に答える 1

19

addStuff'を書きます。これらはそれぞれとに相当します。したがって、これと同等です:(*2) w(+10) ww*2w+10addStuff'

addStuff' w = w*2 >>= \a ->
              w+10 >>= \b ->
              return (a+b)

このように書くと、ここでの左オペランド>>=が関数ではなく数値であることが明らかになります。そのため、推論された型は、関数がモナドである数値に対してのみ機能することを示しています。

do表記を削除する場合、 の左オペランド>>=は の右オペランドとまったく同じである必要があり<-ます。また、表記を削除doしても、関数に引数は追加されません。したがって、正しい書き直しは次のようになります。

addStuff' = (*2) >>= \a ->
            (+10) >>= \b ->
            return (a+b)

以前のコードが機能しない理由については、次のとおりです。

( (*2) >>= (+10) ) 3 

演算子の>>=型はm a -> (a -> m b) -> m bです。簡単にするために、このコードのすべての数値に typeIntがあり、左のオペランドに type Int -> Intor m Intif mis があると仮定しましょう(->) Int。したがって、一部の型bの場合、右側のオペランドには型Int -> ((->) Int) bまたは、より読みやすくする必要がありInt -> Int -> bます。実際に持っている型はInt -> Int. したがって、式の型が正しくありません。

(return 3) :: ((->) Int)

((->) Int)has kind * -> *- 値の型には kind が必要*です。

または、これを別の方法でアプローチするには、いくつかのreturn 3型を持っています (簡単にするために、すべての整数リテラルに型があると仮定しています)。したがって、isの場合、 の型はorになり、 notになります。m IntmIntm((->) Int)return 3((->) Int) IntInt -> Int((->) Int)

于 2013-01-20T23:18:25.540 に答える