【问题标题】:What does " Non type-variable argument in the constraint" really mean?“约束中的非类型变量参数”到底是什么意思?
【发布时间】:2020-03-15 16:20:56
【问题描述】:

例如:

map (+1) 2

在 ghci 产量中

<interactive>:23:1: error:
* Non type-variable argument in the constraint: Num [b]
  (Use FlexibleContexts to permit this)
* When checking the inferred type
    it :: forall b. (Num b, Num [b]) => [b]

我见过许多与我类似的问题,但似乎都只是回答我们可以从中推断出的问题(map 的第二个参数的类型是错误的),以及如何解决它 - 但不是什么错误实际上是 意味着 。究竟哪里出了问题?

【问题讨论】:

  • 当你用谷歌搜索错误时发生了什么?
  • 发生的事情是,我看到,引用,“许多问题与我的相似,但似乎都只是回答我们可以从中推断出的问题(map 的第二个参数的类型是错误的),以及如何修复它 - 但不是错误的实际含义。”
  • 我相信this answer of mine 涵盖了您的大部分问题(那里的类型构造函数是(-&gt;) 而不是[],但问题几乎相同)。

标签: haskell type-deduction


【解决方案1】:

在你的语句的类型推断过程中出现错误。

自从

  1. (+1)Num a =&gt; a -&gt; a 类型
  2. 2Num a =&gt; a 类型
  3. map(a -&gt; b) -&gt; [a] -&gt; [b] 类型

我们知道map (+1) 必须是(Num b) =&gt; [b] -&gt; [b] 类型,因此map (+1) 2 必须是(Num b, Num [b]) =&gt; [b] 类型。但是[b] 不仅仅是一个类型变量,它是某种类型变量的List,其中list 是一个数据构造函数。在不存在列表语法糖的 Haskell 替代版本中,我们可以写成 (Num b, Num (List b))

这是一个问题,因为默认情况下,Haskell 不支持约束的非类型变量参数。所以问题的本质并不是 Haskell 不知道如何映射数字——而是它不允许我们的函数调用产生的类型的值。

但该规则并不是严格需要的。通过在调用 ghci 时添加 -XFlexibleContexts,我们的方法生成的类型现在是允许的。原因是 Haskell 中的文字 2 并不真正代表一个数字 - 它代表一个类型为 Num a =&gt; a 的对象,它是使用 fromIntegral 从 Integral 2 构造的。所以声明map (+1) 2 等价于map (+1) (fromIntegral (2::Integer))。这意味着文字“2”可以代表任何东西,只要适当的实例化——包括列表。

【讨论】:

  • 为什么要通过将结果分配给未使用的变量来“解决”这个问题,而不是一开始就消除调用?
  • 这个答案的后半部分不正确:结果的类型不是Num [Integer],而是更像Num [Integer] =&gt; [Integer];问题 Haskell 不(默认情况下)知道如何映射单个数字,并且 因为您声称它不知道如何显示结果。
  • @DanielWagner ty,纠正了它。到第二部分:那么,你将如何教它这种行为?您将不得不重新定义map,对吗?我不会考虑“教如何绘制地图”,而是“改变地图的含义”
  • @chepner 对于教育目的来说,这是一个纯粹的理论问题。我不知道map (+1) 2 应该产生什么,即使它有效。更多的是关于错误消息的含义/哪里出了问题。
  • @Nearoo 例如,instance Num a =&gt; Num [a] where fromInteger x = [fromInteger x] 将使您的map (+1) 2 “工作”。但我不建议这样做;相反,请更清楚地了解您想要执行的计算,例如从 map (+1) [2] 或您实际想要的任何列表开始。 2 不是一个列表,教编译器假装它似乎是引入细微错误的好方法。
【解决方案2】:

2 的类型为 Num a =&gt; a;我们没有指定a 是什么,只是它必须有一个Num 实例。

map (+1) 的类型为 Num b =&gt; [b] -&gt; [b];我们已经指定了 b 是什么,但它必须有一个 Num 实例。

当我们确定map (+1) 2的类型时,我们基本上是在统一Num a ~ Num b =&gt; [b]

2 ::                  Num a    => a
map (+1) ::    Num b           => [b] -> [b]
map (+1) 2 :: (Num b, Num [b]) =>        [b]

这就是问题所在。 Num 需要像 ab 这样的类型变量,而不是像 [b] 这样的多态类型,作为它的参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-15
    • 2012-04-21
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    相关资源
    最近更新 更多