应用函子作为幺半群函子

Applicative functors as monoidal functors

正如 Hackage for Applicative Functors 中提到的,它们是强松弛幺半群函子。那么为什么他们在 Haskell 中的定义没有这样显示:

class Functor f => MonoidalApplicative f where
  mult :: f a -> f b -> f (a,b)
  unit :: a -> f a 

  starAp :: f (a -> b) -> f a -> f b
  starAp h x = fmap (uncurry ($)) (mult h x)

<*> (starAp) 在乘法方面很容易重建,这个定义对我来说看起来更简单。例如,这里是 Maybe 实例:

instance MonoidalApplicative Maybe where
  mult (Just x) (Just y) = Just (x,y)
  mult _ _ = Nothing

  unit x = Just x

正如在对您的回答的评论中提到的,join>>= 也有类似的故事。当有几种语义上等效的方式来定义某物时,最好总是选择最有效和实用的方式。 Haskell 旨在编写代码,而不是为了证明事情(尽管不幸的是,不知何故 Haskell 仍未成为非常流行的编程语言)。

如果 starAp 有默认实现,几乎没有人会实现它(就像现在 Monad 中的 >> 键入 class 一样)。但是 <*> 是非常有用的操作。它在 applicate 和 monadic 解析器中使用了很多(megaparsecattoparsecoptparse-applicative),我无法想象我的生活 w/o liftA* 加入事物.此操作尽可能高效非常重要。将 starAp 实现为 fmap (uncurry ($)) (mult h x) 可能会给编译器的内联和优化带来困难。

此外,使用 multunit 操作表示 Applicative 并不能真正解决任何问题。显然,mult = liftA2 (,)。但是你的实现

mult (Just x) (Just y) = Just (x,y)

不完全正确。因为你的实现不够懒惰。当仅评估一种情况可能就足够时,您将评估两种情况。所以即使是这个简单的函数,你仍然会搞砸。因此,这种表示形式更糟。