我尝试编写monad,将所有数据节点乘以给定的数字。 我不知道如何正确定义Monad。
module Main where
data LinkedList a = NodeWithoutNext a | Node a (LinkedList a) deriving (Show)
instance Functor LinkedList where
fmap f (NodeWithoutNext x) = NodeWithoutNext (f x)
fmap f (Node a next) = Node (f a) (fmap f next)
instance Applicative LinkedList where
pure = NodeWithoutNext
(NodeWithoutNext f) <*> (NodeWithoutNext x) = NodeWithoutNext (f x)
(NodeWithoutNext f) <*> (Node a next) = Node (f a) (fmap f next)
instance Monad LinkedList where
return = NodeWithoutNext
(NodeWithoutNext a) >>= f = f a
**(Node a next) >>= f = Node (f a) (next >>= f)**
main :: IO ()
main = do
let list = Node 3 (Node 2 (NodeWithoutNext 7))
print (list)
print (list >>= (\x -> NodeWithoutNext (x+200)))
我收到错误 -
Bla.hs:16:39: error:
* Couldn't match type `b' with `LinkedList b'
`b' is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b.
LinkedList a -> (a -> LinkedList b) -> Linked
at Bla.hs:15:24-26
Expected type: LinkedList (LinkedList b)
Actual type: LinkedList b
* In the second argument of `Node', namely `(next >>= f)'
In the expression: Node (f a) (next >>= f)
In an equation for `>>=':
(Node a next) >>= f = Node (f a) (next >>= f)
* Relevant bindings include
f :: a -> LinkedList b (bound at Bla.hs:16:22)
(>>=) :: LinkedList a -> (a -> LinkedList b) -> LinkedLi
(bound at Bla.hs:15:24)
|
16 | (Node a next) >>= f = Node (f a) (next >>= f)
| ^^^^^^^^^^
我需要在这里解决什么? 问题在于**。
答案 0 :(得分:3)
类型系统会抱怨,因为“绑定”运算符Si
具有签名:
>>=
因此,让我们专门针对(>>=) :: Monad m => m a -> (a -> m b) -> m b
:
LinkedList
因此该函数在左侧显示(>>=) :: LinkedList a -> (a -> LinkedList b) -> LinkedList b
,在右侧显示将LinkedList a
(!)映射到a
的函数,我们希望结果为是LinkedList b
。您定义的函数不能这样做:因为如果构造LinkedList b
,结果将是Node (f a) (next >>= f)
。实际上,您将LinkedList (LinkedList b)
应用于f
(列表的头部),这会产生a
(作为LinkedList b
的头部。)
如果我们查看上面的签名,可能会出现一些想法,但最直接的想法可能是实现某种Node
。 “绑定”必须满足以下规则:
concatMap :: [a] -> (a -> [b]) -> [b]
; return a >>= k = k a
;和m >>= return = m
。 m >>= (\x -> k x >>= h) = (m >>= k) >>= h
函数满足三个约束。 (1)如果我们将值concatMap
包装到x
中,并在每个元素(单例列表)上应用LinkedList
,我们将获得一个包含一个列表的列表, f
的结果,但通过使用k a
的{{1}},我们再次将其展平。 (2)如果我们将concat
与concat一起使用,我们将把每个元素包装在一个新的单例列表中,但是连接将再次打开它。
因此我们可以将其实现为:
concatMap
所以这里m >>= return
将遍历instance Monad LinkedList where
return = NodeWithoutNext
(NodeWithoutNext a) >>= f = f a
(Node a next) >>= f = build (f a)
where build (NodeWithoutNext x) = (Node x (next >>= f))
build (Node x xs) = Node x (build xs)
生成的build
,基本上构建一个几乎重复,除了当我们到达终点时,我们将继续联合其余要素的结果。