我正在学习Haskell,并尝试从《 Haskell编程》一书的第一原理中进行练习,而我正在尝试编写适用于Pair类型的应用程序
data Pair a = Pair a a deriving Show
我在网络上看到了其他一些示例,但是我正在尝试一些不同的应用函子,我正在尝试利用这种类型的单曲面结构。这就是我所拥有的
data Pair a = Pair a a deriving (Show, Eq)
instance Functor Pair where
fmap f (Pair x y) = Pair (f x) (f y)
instance Semigroup a => Semigroup (Pair a) where
(Pair x y) <> (Pair x' y') = Pair (x <> x') (y <> y')
instance Applicative Pair where
pure x = Pair x x
(Pair f g) <*> p = fmap f p <> fmap g p
不幸的是,这无法编译:
* No instance for (Semigroup b) arising from a use of `<>'
Possible fix:
add (Semigroup b) to the context of
the type signature for:
(<*>) :: forall a b. Pair (a -> b) -> Pair a -> Pair b
* In the expression: fmap f p <> fmap g p
In an equation for `<*>': (Pair f g) <*> p = fmap f p <> fmap g p
In the instance declaration for `Applicative Pair'
这是我的堆栈;我看不到如何向应用定义中添加类型类约束,我认为使Semigroup的类型对实例足够了。
我看到的其他解决方案就像
Pair (f g) <*> Pair x y = Pair (f x) (g y)
但是这些解决方案没有利用Pair类型的单曲面部分
是否有可能以我不尝试的方式使之适用?
答案 0 :(得分:3)
尽管确实是Applicative
代表单调函子的类(特别是 Hask 是单调函子的内函子),但是Allen&Moronuki不幸地提出了这一点,似乎暗示了它们之间的直接关系。 Monoid
和Applicative
类。 通常没有这种关系! (Writer
类型的确基于Applicative
类定义了一个特定的Monoid
实例,但这是一个非常特殊的情况。)
这产生了a rather extended discussion at another SO question。
“类仿函数”中的“类”是指类别对象上的单项结构,即Haskell类型。即,您可以将任意两种类型组合为元组类型。这本身与Monoid
类无关,它与将单个类型的两个值组合为相同类型的值有关。
Pair
确实允许使用Applicative
实例,但是您不能基于Semigroup
实例,尽管定义实际上看起来非常相似:
instance Applicative Pair where
pure x = Pair x x
Pair f g <*> Pair p q = Pair (f p) (g q)
但是,您现在可以根据以下内容来定义Semigroup
实例 :
instance Semigroup a => Semigroup (Pair a) where
(<>) = liftA2 (<>)
的确,这是对 any 应用程序有效的Semigroup
实例,但通常不是您想要的定义(通常,容器具有自然的组合操作,永远不会触及所包含的元素,例如列表串联)。
答案 1 :(得分:1)
我不认为Pair
是您想要的Applicative
,Applicative
指出
(<*>) :: f (a -> b) -> f a -> f b
应该将所有功能都放在第一位,而您想要
(<*>) :: Semigroup b => f (a -> b) -> f a -> f b.
如果Pair始终是Semigroup
(例如Maybe
或List
),您的推理就很合理,但是您需要Pair
的先决条件-被收容者为Semigroup
。
答案 2 :(得分:0)
正确:Pair
不能以您想要的方式被设置为Applicative
,因为Applicative f
要求{em {1}}对任何 f a
,甚至非a
Semigroup
个。考虑编写一个替代类并实现它:
a