bob*_*bob 3 monads haskell functional-programming applicative monoids
我已阅读此问答但不了解类别理论部分。
到目前为止,这是我的推理:当我查看类型时
F (a -> b) -> F a -> F b
(a -> M b) -> M a -> M b
a -> F a
a -> M a
唯一在类型级别类似于幺半群的部分是类型构造函数,即应用/单子上下文:
// binary operation
F -> F -> F
M -> M -> M
// identity element
F
M
所以我会说 applicatives/monads 就其上下文而言是幺半群的,因为它们将两个相同类型的上下文组合成一个。pure/return创建了一个最小上下文,因此我们可以将其视为类似于幺半群的标识元素的标识上下文,它创建了一个“最小值”。
然而,monads/applicatives 在它们的类型参数中不是幺半群的,因为它们包含了从ato的转换b。
我不确定我的推理是否有意义。让我感到困惑的是,一方面是幺半群,另一方面是应用程序/单子以不同的方式组合事物:
Nothing <> (Just "bar") -- Just "bar"
(++) <$> Nothing <*> (Just "bar") -- Nothing
Nothing >>= (\x -> (Just "bar") >>= (return . (++) x)) -- Nothing
然而,我猜不同的结果值是由于 monoids 将表达式解释为普通值,而 applicatives/monads 将表达式解释为计算(在上面的例子中可能会失败)。
现在在上述 Q&A 中,单子是内函子范畴的幺半群,而 applicatives 是松散的幺半群函子。我不完全理解这一点,但显然应用程序仅部分保留了幺半群结构,而 monad 则完全保留了它。从函数式程序员的角度来看,这种差异的实际含义是什么?
我问这个问题是为了更好地理解 applicative/monads 以及是什么导致不同的表现力。
我们应该弄清楚我们在这里处理三个完全不同的幺半群:
Monoid类的实例。这些是值级 monoids,即您将 Haskell 值(例如列表)组合在一起。从数学上讲,应用程序是幺半群函子,但是幺半群没有什么可以Monoid为之编写实例的;在 Haskell 上下文中,它是由单元类型和元组构造函数构造的类型级幺半群。(请注意,如果您假装 eg和是同一类型,则这只是一个幺半群。)这些元组在类的方法中不直接可见,但这只是因为它们已通过柯里化隐藏。该类的更一般化的公式是()(,)(Int, (String, Bool))((Int, String), Bool)Applicative
class Functor f => Monoidal f where
  funit ::    ()     -> f  ()
  fzip :: (f a, f b) -> f (a,b)
证明这等效于标准Applicative类是一个很好的练习。幺半群
函子的特征实际上是它(,)在进行函子映射时保留了这个幺半群结构,但这与任何特定的 Haskell 幺半群并没有太大关系。
单子,就像一个半幽默的流行术语一样,是内函子范畴中的幺半群。但是,这又另一个幺我们正在谈论的,仿函数的应用程序堆叠的即独异。与 一样Applicative,该类的数学公式略有不同:
class Monoidal m => Monad m where
  pure ::      a  -> m a
  join :: m (m a) -> m a
即这里的幺半群是 的一种应用组合m。
因此,除此之外,在将涉及 monads/applicative 的事物与某些特定的 Haskell monoid 进行比较时,您会得到不同的行为,这真的不应该让我们感到惊讶。在某些情况下,两者都具有相同的行为,但这基本上可以归因于使用了一个实例,该实例将更高级别的幺半群结构退化为某些东西,当与固定的包含类型一起使用时,它同构为非-参数化Monoid实例。