将 Monoid 约束添加到隐藏变量
Adding a Monoid constraint to a hidden variable
我在 Applicative
的 Haskell 本书章节中。我正在为 ZipList
编写 Applicative
实例,我知道我想多了,正在改变我的方法。我的旧方法是:
data List a = Nil | Cons a (List a) deriving (Eq, Show)
newtype ZipList' a =
ZipList' (List a)
deriving (Eq, Show)
instance Applicative ZipList' where
pure a = ZipList' (Cons a Nil)
ZipList' Nil <*> _ = ZipList' Nil
_ <*> ZipList' Nil = ZipList' Nil
(ZipList' (Cons a bs)) <*> (ZipList' (Cons a' bs')) = (ZipList' (Cons (a(a')) Nil)) `mappend` (ZipList' bs <*> ZipList' bs')
我收到错误:
No instance for (Monoid b) arising from a use of ‘mappend’
Possible fix:
add (Monoid b) to the context of
the type signature for:
(<*>) :: forall a b. ZipList' (a -> b) -> ZipList' a -> ZipList' b
• In the expression:
(ZipList' (Cons (a (a')) Nil))
`mappend` (ZipList' bs <*> ZipList' bs')
In an equation for ‘<*>’:
(ZipList' (Cons a bs)) <*> (ZipList' (Cons a' bs'))
= (ZipList' (Cons (a (a')) Nil))
`mappend` (ZipList' bs <*> ZipList' bs')
In the instance declaration for ‘Applicative ZipList'’
我认为这是因为 mappend
使用 Monoid
作为 ZipList
即:
instance Monoid a => Monoid (ZipList' a) where
mempty = pure mempty
mappend = liftA2 mappend
对 a
设置了 Monoid
约束。在 Applicative
实例中,我无法将 a
添加到 class 实例,除非它不再是正确的 Applicative
实例定义。我知道解决方案不正确,但它确实让我想到“我如何在 Applicative
实例中向 ZipList
的参数添加 Monoid
约束?
无需在此处附加任何内容。不要构建列表 Cons x Nil
并附加列表 y
,只需构建 Cons x y
.
let ZipList bs'' = ZipList' bs <*> ZipList' bs'
in ZipList' (Cons (a a') bs'')
关于 monoid-related 错误。这取决于您为您的类型使用的实例 ZipList'
。
如果你使用像
这样的东西
instance Monoid (ZipList' a) where
mempty = ZipList' Nil
mappend (ZipList' Nil) zs = zs
mappend (ZipList' (Cons x xs)) zs = let
ZipList' ys = mappend (Ziplist' xs) zs
in ZipList' (Cons x ys)
那就不用Monoid a
了。
我认为这完全取决于你想要什么样的幺半群。您提到的 Monoid (ZipList' a)
以逐点方式附加两个列表的每个组件,为此我们确实需要 Monoid a
。但是,在应用程序实例中,您不需要那种追加,您需要列表连接。这可以使用上面的 monoid 实例来实现。
也就是说:您发布的实例,按点工作,可能是 ZipList
最自然的实例。但是没有什么能阻止你定义一个 non-instance 函数
appendZipList' :: ZipList' a -> ZipList' a -> ZipList' a
并在您的应用实例中使用它,而不依赖于幺半群。
否则,您可以为连接追加定义 instance Monoid (List a)
,并在应用实例中使用它
let ZipList' bs'' = ZipList' bs <*> ZipList' bs'
in ZipList' (Cons (a a') Nil `mappend` bs'')
我最终消除了 Monoid 要求,并在 Lists 上使用了一个函数,该函数遍历它们并将函数从左侧应用到右侧的值。
zipForMyList :: List (t -> a) -> List t -> List a
zipForMyList _ Nil = Nil
zipForMyList Nil _ = Nil
zipForMyList (Cons f fs) (Cons a as) = (Cons (f a) (zipForMyList fs as))
repeatMyList :: p -> List p
repeatMyList x = xs where xs = Cons x xs
instance Applicative ZipList' where
pure a = ZipList' (Cons a Nil)
ZipList' Nil <*> _ = ZipList' Nil
_ <*> ZipList' Nil = ZipList' Nil
(ZipList' fs) <*> (ZipList' as) = ZipList' (zipForMyList fs as)
我在 Applicative
的 Haskell 本书章节中。我正在为 ZipList
编写 Applicative
实例,我知道我想多了,正在改变我的方法。我的旧方法是:
data List a = Nil | Cons a (List a) deriving (Eq, Show)
newtype ZipList' a =
ZipList' (List a)
deriving (Eq, Show)
instance Applicative ZipList' where
pure a = ZipList' (Cons a Nil)
ZipList' Nil <*> _ = ZipList' Nil
_ <*> ZipList' Nil = ZipList' Nil
(ZipList' (Cons a bs)) <*> (ZipList' (Cons a' bs')) = (ZipList' (Cons (a(a')) Nil)) `mappend` (ZipList' bs <*> ZipList' bs')
我收到错误:
No instance for (Monoid b) arising from a use of ‘mappend’
Possible fix:
add (Monoid b) to the context of
the type signature for:
(<*>) :: forall a b. ZipList' (a -> b) -> ZipList' a -> ZipList' b
• In the expression:
(ZipList' (Cons (a (a')) Nil))
`mappend` (ZipList' bs <*> ZipList' bs')
In an equation for ‘<*>’:
(ZipList' (Cons a bs)) <*> (ZipList' (Cons a' bs'))
= (ZipList' (Cons (a (a')) Nil))
`mappend` (ZipList' bs <*> ZipList' bs')
In the instance declaration for ‘Applicative ZipList'’
我认为这是因为 mappend
使用 Monoid
作为 ZipList
即:
instance Monoid a => Monoid (ZipList' a) where
mempty = pure mempty
mappend = liftA2 mappend
对 a
设置了 Monoid
约束。在 Applicative
实例中,我无法将 a
添加到 class 实例,除非它不再是正确的 Applicative
实例定义。我知道解决方案不正确,但它确实让我想到“我如何在 Applicative
实例中向 ZipList
的参数添加 Monoid
约束?
无需在此处附加任何内容。不要构建列表 Cons x Nil
并附加列表 y
,只需构建 Cons x y
.
let ZipList bs'' = ZipList' bs <*> ZipList' bs'
in ZipList' (Cons (a a') bs'')
关于 monoid-related 错误。这取决于您为您的类型使用的实例 ZipList'
。
如果你使用像
这样的东西instance Monoid (ZipList' a) where
mempty = ZipList' Nil
mappend (ZipList' Nil) zs = zs
mappend (ZipList' (Cons x xs)) zs = let
ZipList' ys = mappend (Ziplist' xs) zs
in ZipList' (Cons x ys)
那就不用Monoid a
了。
我认为这完全取决于你想要什么样的幺半群。您提到的 Monoid (ZipList' a)
以逐点方式附加两个列表的每个组件,为此我们确实需要 Monoid a
。但是,在应用程序实例中,您不需要那种追加,您需要列表连接。这可以使用上面的 monoid 实例来实现。
也就是说:您发布的实例,按点工作,可能是 ZipList
最自然的实例。但是没有什么能阻止你定义一个 non-instance 函数
appendZipList' :: ZipList' a -> ZipList' a -> ZipList' a
并在您的应用实例中使用它,而不依赖于幺半群。
否则,您可以为连接追加定义 instance Monoid (List a)
,并在应用实例中使用它
let ZipList' bs'' = ZipList' bs <*> ZipList' bs'
in ZipList' (Cons (a a') Nil `mappend` bs'')
我最终消除了 Monoid 要求,并在 Lists 上使用了一个函数,该函数遍历它们并将函数从左侧应用到右侧的值。
zipForMyList :: List (t -> a) -> List t -> List a
zipForMyList _ Nil = Nil
zipForMyList Nil _ = Nil
zipForMyList (Cons f fs) (Cons a as) = (Cons (f a) (zipForMyList fs as))
repeatMyList :: p -> List p
repeatMyList x = xs where xs = Cons x xs
instance Applicative ZipList' where
pure a = ZipList' (Cons a Nil)
ZipList' Nil <*> _ = ZipList' Nil
_ <*> ZipList' Nil = ZipList' Nil
(ZipList' fs) <*> (ZipList' as) = ZipList' (zipForMyList fs as)