我怀疑所有适用的,可折叠的幺半群都可以以相同的方式穿过。换句话说,对于满足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。如果有任何相关的错误消息,请告诉我,我会将它们直接移到问题正文中。
答案 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
实例。您的定义适用于列表(以及其他一些类型,例如Traversable
和Data.Sequence.Seq
),因为它们具有非常特殊的结构。
特别是,Data.Vector.Vector
是(以某些懒惰考虑为模)免费幺半群而[a]
a
和pure
满足特定的通用属性:
每当
foldMap
为m
和Monoid
时,f :: a -> m
就是唯一的monoid同态,foldMap f
。
在其他情况下,例如上面的foldMap f . pure = f
,你通常不会最终满足FL
的身份法,尽管我认为你可能会找到一些较弱的条件来解决问题
如果你想干掉你的想法怎么办?最简单的方法是用Traversable
约束替换Monoid (t a)
约束。然后,您可以使用Alternative t
代替empty
和mempty
代替(<|>)
,并且类型(尽管不是法律)应该可以解决。
如果你真的被mappend
困住了,你必须从Data.Constraint.Forall
引进一些更重的机器。您想要说的是每个Monoid
,a
。您可以将其表达为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
写为约束,事情应该更容易解决。