如何根据绑定定义应用?

How to define apply in terms of bind?

在Haskell中,Applicatives被认为比Functor更强,这意味着我们可以像

一样使用Applicative定义Functor
-- Functor
fmap :: (a -> b) -> f a -> f b
fmap f fa = pure f <*> fa

并且 Monad 被认为比 Applicatives 和 Functors 更强大。

-- Functor
fmap :: (a -> b) -> f a -> f b
fmap f fa = fa >>= return . f

-- Applicative
pure :: a -> f a
pure = return

(<*>) :: f (a -> b) -> f a -> f b
(<*>) = ???  -- Can we define this in terms return & bind? without using "ap" 

我读到 Monad 用于排序操作。但我觉得 Monad 唯一能做的就是 Join 或 Flatten,其余功能来自 Applicatives。

join :: m (m a) -> m a
-- & where is the sequencing in this part? I don't get it.

如果Monad真的是为了排序动作那么我们怎么可以定义Applicatives(不认为是严格按顺序操作,某种并行计算)?

因为单子是内函子类别中的幺半群。也有可交换的幺半群,它们不一定需要按顺序工作。这意味着可交换幺半群的 Monad 实例也需要排序?

编辑: 我找到了一个很棒的页面 http://wiki.haskell.org/What_a_Monad_is_not

我们可以复制ap的定义并对其进行脱糖:

ap f a = do
   xf <- f
   xa <- a
   return (xf xa)

因此,

f <*> a = f >>= (\xf -> a >>= (\xa -> return (xf xa)))

(为清楚起见添加了一些多余的括号。)

If Monad is really for sequencing actions then How come we can define Applicatives (which are not considered to strictly operate in sequence, some kind of parallel computing)?

不完全是。所有 monad 都是 applicatives,但只有一些 applicatives 是 monad。因此,给定一个 monad,您始终可以根据 bindreturn 定义应用实例,但是如果您拥有的只是应用实例,那么您无法在没有更多信息的情况下定义 monad。

monad 的应用实例如下所示:

instance (Monad m) => Applicative m where
   pure = return
   f <*> v = do
      f' <- f
      v' <- v
      return $ f' v'

当然这会按顺序计算 fv,因为它是一个 monad,而这就是 monad 所做的。如果此应用程序不按顺序执行操作,则它不是 monad。

现代 Haskell,当然,是相反的定义:Applicative 类型类是 Functor 的子集,所以如果你有一个 Functor 并且你可以定义 (<*>) 然后你可以创建一个 Applicative 实例。 Monad 又被定义为 Applicative 的子集,因此如果您有一个 Applicative 实例并且您可以定义 (>>=) 那么您可以创建一个 Monad 实例.但是您不能根据 (<*>).

定义 (>>=)

有关详细信息,请参阅 Typeclassopedia

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

(<*>) = ??? -- Can we define this in terms return & bind? without using "ap"

回想一下,<*> 具有 f (a -> b) -> f a -> f b 的类型签名,而 >>= 具有 m a -> (a -> m b) -> m b。那么我们如何从 m a -> (a -> m b) -> m b 推断出 m (a -> b) -> m a -> m b 呢?

>>=定义f <*> x>>=的第一个参数显然应该是f,所以我们可以写出第一个转换:

f <*> x = f >>= k      -- k to be defined

其中函数 k 将类型为 a -> b 的函数作为参数,并且 returns 是 m b 的结果,这样整个定义与bind >>= 的类型签名。对于k,我们可以这样写:

k :: (a -> b) -> m b
k = \xf -> h x          

请注意,函数 h 应该使用 f <*> x 中的 x,因为 x 在某种程度上与 m b 的结果相关,就像函数一样xfa -> b

对于h x,很容易得到:

h :: m a -> m b
h x = x >>= return . xf

把以上三个定义放在一起,我们得到:

f <*> x = f >>= \xf -> x >>= return . xf

所以即使你不知道ap的定义,你仍然可以根据类型签名得到@chi所示的最终结果。