You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

给定Applicative f却无法推导Applicative f0,咨询代码中独立约束问题

解答你的Haskell类型推导与Reducers包约束问题

一、「Could not deduce (Applicative f0)」错误分析

这个错误本质是编译器找不到某个隐式类型变量的具体实例绑定——哪怕你已经显式指定了Applicative f约束,也可能因为代码中存在未明确标注的类型上下文,导致编译器生成一个全新的、无约束的临时类型变量f0

结合你提到的Data.Semigroup.Applicative(核心是Ap这个newtype),大概率是在使用Ap相关代码时,没有给它绑定具体的Applicative实例。比如假设你的apm代码类似这样:

apm :: (Applicative f) => Ap f (Max Int)
apm = Ap (pure (Max 3))

如果没有在签名里明确指定f的具体类型(比如Maybe[]),也没有在使用apm的地方提供足够的类型线索,编译器就会抛出这个错误——这里的f0是它临时生成的、和你指定的f完全无关的未约束变量。

解决思路:

  • 要么显式给apm的类型签名绑定具体实例,比如apm :: Ap Maybe (Max Int)
  • 要么在调用apm的位置补充类型上下文,让编译器能推断出f的具体实现。

二、为何会出现两个独立的Applicative约束ff0

要搞懂这个问题,得结合reducers包的设计和Ap类型的作用来看:

  1. Ap newtype的核心作用
    Ap f a是一个包装器,它能把Applicative f的实例转换成Semigroup(甚至Monoid)实例。当a本身是Semigroup时,Ap f a<>操作会通过liftA2 (<>)实现,mempty则是pure mempty

  2. Reducer类型类的约束传递
    你的bar函数签名是:

    bar :: (Foldable f, Monoid m, Reducer e m) => f e -> m
    

    mAp f0 a类型时,Reducer e (Ap f0 a)的实例会要求Applicative f0作为约束;而如果你的函数本身又显式指定了Applicative f的约束(比如apm的定义),就会出现两个独立的类型变量:

    • f是你当前函数显式声明的Applicative上下文;
    • f0Ap包装器内部的Applicative上下文,属于Reducer实例为了处理Ap类型而引入的额外约束。

简单说,这两个约束来自不同的层级:一个是函数自身的上下文要求,另一个是Reducer实例为支持Ap类型而自动引入的,二者是完全独立的类型变量,所以会同时出现在签名里。

补充:你的代码小细节说明

看你的foo函数:

foo :: [String] -> (Max Int)
foo = foldReduce . map length

它能正常工作是因为Reducer Int (Max Int)存在现成实例(Max IntMonoidInt可以通过unit方法转换成Max Int),foldReduce会把map length生成的[Int]折叠成最终的Max Int,完全符合预期。

m = unit (2 :: Int)也没问题,这里Reducer Int (Max Int)实例会自动把整数2转换成Max 2

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

火山引擎 最新活动