簡體   English   中英

嘗試使用幺半群仿函數的應用實例

[英]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不幸地以某種方式提出了這一點,似乎暗示了MonoidApplicative類之間的直接關系。 通常,沒有這種關系 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 (例如MaybeList ),則您的推理是合理的,但您需要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 開始派生,其中包括通孔類型GenericallyGenerically1 這將派生出與 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提升SemigroupMonoid

  deriving (Semigroup, Monoid, Num)
  via Ap Pair a

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM