[英]Applicative instance trying to use monoidal functors
我正在學習 Haskell 並嘗試從書 Haskell 中進行練習 從第一原則開始編程 我正在嘗試為 Pair 類型編寫應用程序
data Pair a = Pair a a deriving Show
我在 web 上看過其他一些例子,但我正在嘗試一些不同的應用函子,我正在嘗試利用這種類型的幺半群結構。 這是我所擁有的
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 實例就足夠了。
我見過的其他解決方案就像
Pair (f g) <*> Pair x y = Pair (f x) (g y)
但這些解決方案不使用 Pair 類型的幺半群部分
甚至可以按照我嘗試的方式使這個應用程序可用嗎?
盡管確實Applicative
是代表單曲面仿函數(特別是Hask endofunctors是單曲面)的類,但是Allen&Moronuki不幸地以某種方式提出了這一點,似乎暗示了Monoid
和Applicative
類之間的直接關系。 通常,沒有這種關系 ! ( Writer
類型的確基於Monoid
類定義了一個特定的Applicative
實例,但這是一種非常特殊的情況。)
這引發了對另一個SO問題的廣泛討論 。
“單調仿函數”中的“單調”是指類別對象 (即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 (<>)
的確,對於任何應用程序而言,這都是一個有效的Semigroup
實例,但通常不是您想要的定義(通常,容器具有自然的組合操作,永遠不會觸及所包含的元素,例如列表串聯)。
我不認為這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
。
正確: Pair
不能以您想要的方式變為Applicative
,因為Applicative f
要求fa
對任何 a
甚至非Semigroup
a
“感到適用y”。 考慮編寫替代類並實現它:
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
這可以從 base 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.