我在Applicative
的Haskell Book章节中。我正在为Applicative
编写ZipList
个实例,我知道我已经推翻了它并正在改变我的方法。我的老方法是:
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
会在Monoid
上设置a
约束。在Applicative
实例中,我无法将a
添加到类实例,而不会使其不再是正确的Applicative
实例定义。我知道解决方案不正确,但它确实让我想到“如何在Monoid
实例中向ZipList
的参数添加Applicative
约束?
答案 0 :(得分:2)
没有必要在这附加任何东西。不要构建列表<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/timepicker/1.3.5/jquery.timepicker.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/timepicker/1.3.5/jquery.timepicker.min.js"></script>
<input type="text" maxlength="8" placeholder="" class="time-icn form-control ui-timepicker-input valid" name="ReminderTime" id="ReminderTime" class="ReminderTime" value="" autocomplete="off">
并附加列表Cons x Nil
,只需构建y
。
Cons x y
关于与幺半群有关的错误。这取决于您为类型let ZipList bs'' = ZipList' bs <*> ZipList' bs'
in ZipList' (Cons (a a') bs'')
使用的实例。
如果您使用类似
的内容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实例来实现。
话虽如此:你发布的实例,点工作,可能是Monoid a
最自然的。但是,没有什么能阻止您定义非实例函数
ZipList
并在您的应用实例中使用它,而不依赖于幺半群。
否则,您可以为连接追加定义appendZipList' :: ZipList' a -> ZipList' a -> ZipList' a
,并在应用实例中使用它
instance Monoid (List a)
答案 1 :(得分:0)
我最终消除了Monoid的要求并在Lists上使用了一个函数,它们将它们从左边的funcs应用到右边的值。
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)