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

如何让GHCi告知`allEqual <*> reverse`中使用的Applicative实例?

函数式编程问题:确定allEqual <*> reverse使用的Applicative实例

GHCi交互记录

> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
> :t allEqual
allEqual :: Eq a => [a] -> [a] -> Bool
> :t allEqual <*> reverse
allEqual <*> reverse :: Eq a => [a] -> Bool
> :t reverse
reverse :: [a] -> [a]

问题

我想要确定allEqual <*> reverse中具体使用的Applicative实例是什么。我尝试进行推理:

f (a -> b) :: [a] -> [a] -> Bool
f a :: [a] -> [a]
f b :: [a] -> Bool

但这个推理并不合理,因为f b与a相关。请问有没有办法让GHCi直接告知此处实际使用的Applicative实例f是什么?如果没有的话,Haskell开发者通常是如何推理这类问题的?


解答

让GHCi验证Applicative实例的方法

GHCi没有直接命令输出具体的Applicative实例,但可以通过类型约束验证的方式确认:

  1. 开启类型应用扩展,手动指定实例类型进行验证:
> :set -XTypeApplications
> :t allEqual <*> reverse :: Eq a => (-> [a]) Bool
allEqual <*> reverse :: Eq a => [a] -> Bool

如果没有报错,说明(->) [a](函数类型的Applicative实例,即Reader实例)是正确的。
2. 开启详细类型打印,查看隐含约束:

> :set -fprint-explicit-foralls -fprint-explicit-kinds
> :t allEqual <*> reverse
allEqual <*> reverse :: forall a. Eq a => [a] -> Bool

虽然不会直接写出f的类型,但结合推导可以确认实例。

手动推理的思路

这里使用的是函数类型(->) r的Applicative实例,推导步骤如下:

  • 把allEqual的类型改写为Eq a => (->) [a] ([a] -> Bool),对应Applicative类型签名里的f (x -> y),其中f = (->) [a],x -> y = [a] -> Bool。
  • 把reverse的类型改写为(->) [a] [a],对应Applicative签名里的f x,其中x = [a]。
  • 函数类型的<*>实现逻辑是:(<*>) f g x = f x (g x),也就是将同一个输入x传给两个函数,用前者的输出(函数)调用后者的输出。对应到本例就是\x -> allEqual x (reverse x),最终类型为[a] -> Bool,和GHCi的输出完全匹配。

简单总结:当<*>两侧都是函数类型时,几乎必然使用的是(->) r这个Applicative实例,它的作用是组合两个共享输入的函数,生成新函数。


内容的提问来源于stack exchange,提问作者Tom Huntington

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:31:15