这两种函数类型定义有什么区别?

McB*_*den 5 haskell

对于以下简单的函数定义:

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


printLength2::String->Int
printLength2 s = length s
Run Code Online (Sandbox Code Playgroud)

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

我得到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
Run Code Online (Sandbox Code Playgroud)

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

Tik*_*vis 9

第一种类型的签名更为通用.这意味着结果可以是任何Num- 它的返回类型是多态的.所以,你的第一个函数的结果可以作为一个Int或一个Integer或任何其他Num实例.

问题是length返回一个Int而不是任何Num实例.您可以使用fromIntegral以下方法修复此

printLength1 :: Num a => String -> a
printLength1 s = fromIntegral $ length s
Run Code Online (Sandbox Code Playgroud)

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

  • @osager这不是一个怪癖,这是类型系统中一个非常重要的部分.多态类型(至少是1级多态类型)根据它们的使用方式变成具体类型.如果你写一个声称类型是多态的类型签名,它实际上需要*是*多态的. (3认同)

Vin*_*ard 7

引用LearnYouAHaskell.com:

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