Ran*_*ize 1 monads haskell functor applicative
我是Haskell的新手,我正在努力更好地理解functor,applicative和monad是如何协同工作的.在我的例子中:
import Control.Monad
import Control.Applicative
data FooBar a = Foo a | Bar a deriving (Show)
myf :: FooBar Int -> FooBar Int
myf (Bar a) = Foo (a * 10)
myf (Foo a) = Bar (a * 10)
instance Functor FooBar where
fmap func (Foo val) = Bar (func val)
fmap func (Bar val) = Foo (func val)
instance Applicative FooBar where
pure = Foo
(Foo f) <*> (Foo x) = Foo (f x)
(Foo f) <*> (Bar x) = Foo (f x)
(Bar f) <*> (Foo x) = Bar (f x)
(Bar f) <*> (Bar x) = Bar (f x)
instance Monad FooBar where
return = Foo
(Foo x) >>= f = f x
(Bar x) >>= f = f x
main = putStrLn $ show $ Foo (+3) <*> Foo 5 >>= myf
Run Code Online (Sandbox Code Playgroud)
我想要实现的是通过monad的绑定从Functor/Applicative中"管道"值但是我main在行中出错:
ghc: No instance for (Num (FooBar Int)) arising from a use of `+'
Possible fix: add an instance declaration for (Num (FooBar Int))
In the first argument of `Foo', namely `(+ 3)'
In the first argument of `(<*>)', namely `Foo (+ 3)'
In the first argument of `(>>=)', namely `Foo (+ 3) <*> Foo 5'
Run Code Online (Sandbox Code Playgroud)
如果我用这样的Functor替换Applicative会发生类似的事情:
main = putStrLn $ show $ (+3) <$> Foo 5 >>= myf
Run Code Online (Sandbox Code Playgroud)
实际上我可能会做什么,或者我的定义中有错误?
编辑 这是一个更清洁的解决方案:
import Control.Monad
import Control.Applicative
data FooBar a = Foo a | Bar a deriving (Show)
myf :: Int -> FooBar Int
myf (a) = return (a * 10)
instance Functor FooBar where
fmap func (Foo val) = Foo (func val)
fmap func (Bar val) = Bar (func val)
instance Applicative FooBar where
pure = Foo
(Foo f) <*> something = fmap f something
(Bar f) <*> something = fmap f something
instance Monad FooBar where
return = Foo
(Foo x) >>= f = f x
(Bar x) >>= f = f x
main = putStrLn $ show $ (+) <$> Bar(19) <*> (Foo 3) >>= myf
Run Code Online (Sandbox Code Playgroud)
问题出在这里:
myf :: FooBar Int -> FooBar Int
Run Code Online (Sandbox Code Playgroud)
以上使用时会造成麻烦
something >>= myf
Run Code Online (Sandbox Code Playgroud)
因为它需要something有类型FooBar (FooBar Int).这反过来使数字常量是类型FooBar Int而不是Int,并对(+)类型的"数字"进行操作FooBar Int.这会触发类型错误.
也许你只是想用
myf something
Run Code Online (Sandbox Code Playgroud)
代替.在你的特定情况下,
main = putStrLn $ show $ myf $ Foo (+3) <$> Foo 5
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
139 次 |
| 最近记录: |