将Monoid约束添加到隐藏变量

时间:2018-04-07 05:22:54

标签: haskell applicative monoids

我在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约束?

2 个答案:

答案 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)