【问题标题】:Applicative instance trying to use monoidal functors尝试使用幺半群函子的应用实例
【发布时间】:2018-08-03 11:29:02
【问题描述】:

我正在学习 Haskell 并尝试从 Haskell Programming 一书中从第一原理开始做练习,我正在尝试为 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'

这就是我的堆栈;我看不到如何将 typeclass 约束添加到 Applicative 定义中,我认为制作 Semigroup 的类型 Pair 实例就足够了。

我见过的其他解决方案是这样的

Pair (f g) <*> Pair x y = Pair (f x) (g y)

但这些解决方案不使用 Pair 类型的单曲面部分

是否有可能以我不尝试的方式进行应用?

【问题讨论】:

  • 我可能是错的,但我认为您使用的术语“monoidal functor”指的是 actual definition 以外的其他东西。
  • 您遇到了同样的问题,这意味着 Set 不能是 Monad(或 Applicative),因此围绕该问题的许多讨论也应该在网上流传对你来说很有趣。考虑在谷歌上搜索“受约束的单子”以获得很多很多起点。

标签: haskell applicative monoids


【解决方案1】:

虽然Applicative 确实是代表幺半群函子的类(具体来说,是单群的 Hask 内函子),但不幸的是,Allen&Moronuki 以一种似乎暗示 @ 之间的直接关系的方式呈现了这一点987654323@ 和 Applicative 类。 一般来说,没有这样的关系! (Writer 类型确实基于 Monoid 类定义了一个特定的 Applicative 实例,但这是一种极其特殊的情况。)
这产生了a rather extended discussion at another SO question

“monoidal functor”中的“monoidal”指的是类别对象上的monoidal结构,即在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 实例,但它通常不是您想要的定义(通常,容器具有从不触及包含的元素的自然组合操作,例如列表连接)。

【讨论】:

  • 谢谢!作为初学者,有点难以理解讨论,但我想我理解了其中的一部分:应用实例应该适用于实现它的所有类型,而我的实现取决于类型应该实现 Semigroup 实例的事实(所有类型,无论它们有多深在结构中)第二个“monoidal”部分应该是关于结构(在我的情况下它是 Pair 构造函数)而不是我试图组合的值(这就是 Monoid 正在做的)
【解决方案2】:

我不认为Pair 是您想要的ApplicativeApplicative 表示

(<*>) :: f (a -> b) -> f a -> f b

应该适用于你想要的所有功能

(<*>) :: Semigroup b => f (a -> b) -> f a -> f b.

如果 Pair 始终是 Semigroup(例如 MaybeList),您的推理将是合理的,但您需要 Pair-containee 的先决条件是 Semigroup

【讨论】:

    【解决方案3】:

    正确:Pair 不能以您想要的方式成为 Applicative,因为 Applicative f 要求 f a任何 a“感觉适用” ,甚至非Semigroupas。考虑编写一个替代类并实现它:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-05
      • 2014-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-01
      相关资源
      最近更新 更多