【问题标题】:What's the difference between these two function type definitions?这两个函数类型定义有什么区别?
【发布时间】:2011-11-30 00:53:17
【问题描述】:

对于以下琐碎的函数定义:

printLength1::(Num a)=>String->a
printLength1 s = length s


printLength2::String->Int
printLength2 s = length s

为什么它们不一样?在什么情况下我应该选择一个而不是另一个?

我得到 printLength1 这个错误:

Couldn't match type `a' with `Int'
      `a' is a rigid type variable bound by
          the type signature for rpnc :: String -> a at test.hs:20:1
    In the return type of a call of `length'
    In the expression: length s
    In an equation for `rpnc': rpnc s = length s

我理解这个错误。但我该如何解决这个问题? 我已经在这里阅读了一些关于刚性类型变量的帖子,但仍然不明白如何修复它。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    第一种类型签名更通用。这意味着结果可以是任何Num——它的返回类型是多态的。因此,您的第一个函数的结果可以用作IntInteger 或任何其他Num 实例。

    问题在于length 返回一个Int 而不是任何Num 实例。您可以使用fromIntegral 解决此问题:

    printLength1 :: Num a => String -> a
    printLength1 s = fromIntegral $ length s
    

    注意fromIntegral . length(上面代码的无点版本)的签名是Num c => [a] -> c。这与您为 printLength1 函数指定的签名相匹配。

    【讨论】:

    • 谢谢大家。我希望语言中不再隐藏这样的怪癖。
    • @osager 这不是一个怪癖,这是类型系统中非常重要的一部分。多态类型(至少 rank-1 多态类型)通过它们的使用方式变成具体类型。如果您编写的类型签名声称一个类型是多态的,那么它实际上需要多态的。
    • Num 类并不是一个怪癖,但您可以合理地争辩说 length 是一个 Int 而不是 Num a 是一个怪癖。
    • Data.List.genericLength 的类型为 Num a => [b] -> a
    • @Grazer:很高兴知道。事实上,length 必须有一个特殊的通用版本,这表明它有点怪癖。
    【解决方案2】:

    引用LearnYouAHaskell.com:

    注意:此函数的类型为 numLongChains :: Int,因为由于历史原因,长度返回 Int 而不是 Num a。如果我们想返回一个更一般的 Num a,我们可以对结果长度使用 fromIntegral。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-19
      • 2011-02-20
      • 2013-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多