表达满足多个约束的任何类型的实例

时间:2018-05-01 02:20:22

标签: haskell typeclass

我怀疑所有适用的,可折叠的幺半群都可以以相同的方式穿过。换句话说,对于满足t :: * -> *Applicative并且所有实例化Foldable都满足t a的任何类型Monoid,都有一个免费的{ {1}}。

以下是我将如何实施Traversable

sequenceA

我们可以例如使用它来遍历包含函数的列表到一个将生成列表的函数(因为sequenceA :: (Applicative t, Foldable t, Monoid (t a), Applicative f) => t (f a) -> f (t a) sequenceA = foldl (liftA2 $ \b a -> mappend b (pure a)) (pure mempty) 是适用的,可折叠的,并且对所有类型[]都是monoid:

[a]

不幸的是,我无法弄清楚如何使用此sequenceA [\a -> 2 * a, \a -> 2 + a] $ 5 -- [10, 7] 的实现来实际指定Traversable实例。这是我试过的:

sequenceA

如果我尝试编译它而没有任何扩展,我得到:

instance (Applicative t, Foldable t, Monoid (t a)) => Traversable t where
  sequenceA = foldl (liftA2 $ \b a -> mappend b (pure a)) (pure mempty)

在Haskell中表达此实例的正确方法是什么?

关于递归添加编译器错误提到的任何扩展可能解决问题的机会,我尝试了并尝试粘贴结果here。如果有任何相关的错误消息,请告诉我,我会将它们直接移到问题正文中。

1 个答案:

答案 0 :(得分:4)

你的推测是错误的。考虑类型

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import Data.Semigroup
import Data.Monoid hiding ((<>))

newtype FL a = FL [a] deriving (Functor, Foldable, Applicative)
instance Semigroup (FL a) where
  FL as <> FL bs = FL $ as ++ drop (length as) bs
instance Monoid (FL a) where
  mempty = FL []
  mappend = (<>)

这基于Alternative的{​​{1}}个实例。 ZipList显然是mempty的标识,mappend的关联性稍差,因此它是一个有效的mappend实例。但是,使用您的定义会导致有效的Monoid实例。您的定义适用于列表(以及其他一些类型,例如TraversableData.Sequence.Seq),因为它们具有非常特殊的结构。

特别是,Data.Vector.Vector是(以某些懒惰考虑为模)免费幺半群[a] apure满足特定的通用属性:

  

每当foldMapmMonoid时,f :: a -> m就是唯一的monoid同态,foldMap f

在其他情况下,例如上面的foldMap f . pure = f,你通常不会最终满足FL的身份法,尽管我认为你可能会找到一些较弱的条件来解决问题

如果你想干掉你的想法怎么办?最简单的方法是用Traversable约束替换Monoid (t a)约束。然后,您可以使用Alternative t代替emptymempty代替(<|>),并且类型(尽管不是法律)应该可以解决。

如果你真的被mappend困住了,你必须从Data.Constraint.Forall引进一些更重的机器。您想要说的是每个Monoida。您可以将其表达为Monoid (t a)。但是,您不能在该约束下使用ForallF Monoid t方法,因为Monoid本身不支持它。相反,您必须使用GHC

instF

当然,一旦你遇到了所有麻烦,你会发现你的{-# LANGUAGE TypeOperators, ScopedTypeVariables, InstanceSigs, ... #-} import Data.Constraint import Data.Constraint.Forall instance (Applicative t, Foldable t, ForallF Monoid t) => Traversable t where sequenceA :: forall f a. Applicative f => t (f a) -> f (t a) sequenceA = case instF :: ForallF Monoid t :- Monoid (t a) of Sub Dict -> foldl (liftA2 $ \b a -> mappend b (pure a)) (pure mempty) 实例与所有其他 Traversable实例重叠,这几乎是彻底的灾难。

附录:作为Benjamin Hodgson notes,有一个被接受的GHC proposal来支持量化(和暗示)约束。如果实现(可能很快),您将能够简单地将Traversable写为约束,事情应该更容易解决。