尝试使用幺半群仿函数的应用实例
Applicative instance trying to use monoidal functors
我正在学习 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'
这就是我的堆栈;我不知道如何将类型类约束添加到 Applicative 定义中,我认为制作 Semigroup 的类型对实例就足够了。
我看到的其他解决方案如
Pair (f g) <*> Pair x y = Pair (f x) (g y)
但是这些解决方案不使用 Pair 类型的幺半群部分
是否有可能按照我尝试的方式制作此应用程序?
我不认为 Pair
是 Applicative
你想要的样子,Applicative
说
(<*>) :: f (a -> b) -> f a -> f b
应该适用于第一位置的所有功能,而您想要
(<*>) :: Semigroup b => f (a -> b) -> f a -> f b.
如果 Pair 始终是 Semigroup
(例如 Maybe
或 List
),您的推理是合理的,但您需要先决条件 Pair
-containee 为 Semigroup
.
虽然 Applicative
确实是 class 代表幺半群的函子(具体来说,Hask 内函子是幺半群的),Allen&Moronuki 不幸地在一个这似乎表明 Monoid
和 Applicative
class 之间存在直接关系。 一般来说,没有这种关系! (Writer
类型确实定义了一个基于 Monoid
class 的特定 Applicative
实例,但这是一种极其特殊的情况。)
这产生了 .
“幺半群函子”中的“幺半群”指的是类别对象上的幺半群结构,即Haskell类型上的幺半群结构。也就是说,您可以将任意两种类型组合成一个元组类型。这本身与 Monoid
class 没有任何关系,Monoid
class 是关于将单个类型的两个 值 组合成相同类型的值。
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
实例,但它通常不是您想要的定义(通常,容器具有自然组合操作从不触及包含的元素,例如列表连接)。
正确:Pair
无法按照您想要的方式成为 Applicative
,因为 Applicative f
要求 f a
"feel applicative-y" 任何 a
,甚至非Semigroup
a
。考虑编写替代方案 class 并实施它:
class CApplicative f where
type C f
pure :: C f a => a -> f a
app :: C f b => f (a -> b) -> f a -> f b
instance CApplicative Pair where
type C Pair = Semigroup
pure x = Pair x x
app (Pure f g) p = fmap f p <> fmap g p
这可以从基础 4.17.0.0 开始派生,其中包括过孔类型 Generically
和 Generically1
。这将派生出与 leftaroundabout 所写的相同的实例:
{-# Language DeriveGeneric #-}
{-# Language DerivingStrategies #-}
{-# Language DerivingVia #-}
import Data.Monoid
import GHC.Generics
data Pair a = Pair a a
deriving
stock (Generic, Generic1)
deriving (Semigroup, Monoid)
via Generically (Pair a)
deriving (Functor, Applicative)
via Generically1 Pair
或者您可以通过 Applicative
提升 Semigroup
和 Monoid
deriving (Semigroup, Monoid, Num)
via Ap Pair a
我正在学习 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'
这就是我的堆栈;我不知道如何将类型类约束添加到 Applicative 定义中,我认为制作 Semigroup 的类型对实例就足够了。
我看到的其他解决方案如
Pair (f g) <*> Pair x y = Pair (f x) (g y)
但是这些解决方案不使用 Pair 类型的幺半群部分
是否有可能按照我尝试的方式制作此应用程序?
我不认为 Pair
是 Applicative
你想要的样子,Applicative
说
(<*>) :: f (a -> b) -> f a -> f b
应该适用于第一位置的所有功能,而您想要
(<*>) :: Semigroup b => f (a -> b) -> f a -> f b.
如果 Pair 始终是 Semigroup
(例如 Maybe
或 List
),您的推理是合理的,但您需要先决条件 Pair
-containee 为 Semigroup
.
虽然 Applicative
确实是 class 代表幺半群的函子(具体来说,Hask 内函子是幺半群的),Allen&Moronuki 不幸地在一个这似乎表明 Monoid
和 Applicative
class 之间存在直接关系。 一般来说,没有这种关系! (Writer
类型确实定义了一个基于 Monoid
class 的特定 Applicative
实例,但这是一种极其特殊的情况。)
这产生了
“幺半群函子”中的“幺半群”指的是类别对象上的幺半群结构,即Haskell类型上的幺半群结构。也就是说,您可以将任意两种类型组合成一个元组类型。这本身与 Monoid
class 没有任何关系,Monoid
class 是关于将单个类型的两个 值 组合成相同类型的值。
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
实例,但它通常不是您想要的定义(通常,容器具有自然组合操作从不触及包含的元素,例如列表连接)。
正确:Pair
无法按照您想要的方式成为 Applicative
,因为 Applicative f
要求 f a
"feel applicative-y" 任何 a
,甚至非Semigroup
a
。考虑编写替代方案 class 并实施它:
class CApplicative f where
type C f
pure :: C f a => a -> f a
app :: C f b => f (a -> b) -> f a -> f b
instance CApplicative Pair where
type C Pair = Semigroup
pure x = Pair x x
app (Pure f g) p = fmap f p <> fmap g p
这可以从基础 4.17.0.0 开始派生,其中包括过孔类型 Generically
和 Generically1
。这将派生出与 leftaroundabout 所写的相同的实例:
{-# Language DeriveGeneric #-}
{-# Language DerivingStrategies #-}
{-# Language DerivingVia #-}
import Data.Monoid
import GHC.Generics
data Pair a = Pair a a
deriving
stock (Generic, Generic1)
deriving (Semigroup, Monoid)
via Generically (Pair a)
deriving (Functor, Applicative)
via Generically1 Pair
或者您可以通过 Applicative
Semigroup
和 Monoid
deriving (Semigroup, Monoid, Num)
via Ap Pair a