You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中Applicative的*>实现:类型匹配与列表转换疑问

关于Haskell中Applicative实例(*>)实现的疑问

我正在通过fp-course的练习学习Haskell,在填充Application.hs中的(*>)函数时,看不懂给出的答案:

-- | Apply, discarding the value of the first argument.
-- Pronounced, right apply.
--
-- >>> (1 :. 2 :. 3 :. Nil) *> (4 :. 5 :. 6 :. Nil)
-- [4,5,6,4,5,6,4,5,6]
--
-- >>> (1 :. 2 :. Nil) *> (4 :. 5 :. 6 :. Nil)
-- [4,5,6,4,5,6]
--
-- >>> (1 :. 2 :. 3 :. Nil) *> (4 :. 5 :. Nil)
-- [4,5,4,5,4,5]
--
-- >>> Full 7 *> Full 8
-- Full 8
--
-- prop> \a b c x y z -> (a :. b :. c :. Nil) *> (x :. y :. z :. Nil) == (x :. y :. z :. x :. y :. z :. x :. y :. z :. Nil)
--
-- prop> \x y -> Full x *> Full y == Full y
(*>) ::
  Applicative k =>
  k a
  -> k b
  -> k b
(*>) ka kb = (pure id) <$> ka <*> kb

以k为List为例,我有两个疑问:

  1. 为何<$>的第一个参数类型(a -> a)能够接受类型为List (a -> a)的pure id?
  2. 我不理解为何(pure id) <$> ka能将1 :. 2 :. 3 :. Nil转换为id :. id :. id :. Nil?

解答

疑问1的澄清

你混淆了<$>的参数类型和作用:

  • <$>(即fmap)的类型是Functor f => (x -> y) -> f x -> f y,它的第一个参数必须是普通函数,而非Functor容器值。
  • pure id的类型是Applicative k => k (b -> b),是一个容器值,直接把它作为<$>的第一个参数不符合类型要求——这说明你看到的代码大概率存在笔误,正确的实现应该是用const id(类型为a -> (b -> b)的函数,接受任意a类型值,返回id函数)替代pure id,即:
    (*>) ka kb = (const id) <$> ka <*> kb
    
    如果你看到的代码确实是(pure id) <$> ka,那可能是把<$>和<$搞混了——x <$ y是const x <$> y的语法糖,(pure id) <$ ka等价于const (pure id) <$> ka,此时第一个参数是const (pure id),类型为a -> k (b -> b),符合<$>的要求。

疑问2的解释

如果是正确的const id <$> ka:

  • const id的作用是忽略输入值,直接返回id函数。对于List类型来说,const id <$> (1 :. 2 :. 3 :. Nil)会把列表中的每个元素都替换成id函数,最终得到id :. id :. id :. Nil。
  • 之后<*> kb会把每个id函数应用到kb的所有元素上,对于List的Applicative实例来说,就是做笛卡尔积运算,最终得到kb重复ka长度次的结果,和示例输出一致。

如果是你看到的(pure id) <$> ka:

  • 它的结果会是(pure id) :. (pure id) :. (pure id) :. Nil,也就是[[id], [id], [id]](List嵌套List的函数容器),之后<*> kb虽然也能得到示例中的结果,但这不是(*>)的常规实现方式,且类型推导上需要额外的层级处理,显然不合理。

内容的提问来源于stack exchange,提问作者zichao liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:33:07