Haskell类型错误匹配Num a和Int

时间:2016-03-13 13:46:25

标签: haskell

为什么我不能这样做?

genList :: Num a => Int -> [a]
genList m_size = [1..m_size]

它说:

 Couldn't match expected type `a' with actual type `Int'
      `a' is a rigid type variable bound by
          the type signature for genList :: Num a => Int -> [a]
          at uloha1.hs:105:12
    Relevant bindings include
      genList :: Int -> [a] (bound at uloha1.hs:106:1)
    In the expression: m_size
    In the expression: [1 .. m_size]

为什么它不能隐式重新输入Int到Num? Int是Num的例子不是吗? 我找不到任何相关内容。 我正在使用最新的Haskell平台Ghci 我也是哈斯克尔的新手。

5 个答案:

答案 0 :(得分:3)

Haskell永远不应该“重新输入”任何东西。您可能会将此与多态数字文字混淆。但是,m_size不是文字,而是明确Int。你可以写

[1 .. fromIntegral m_size]

但是你仍然存在这个构造还需要Enum约束的问题。

另一种选择是

genList :: Enum a => Int -> [a]
genList m_size = [toEnum 1 .. toEnum m_size]

由于这适用于任何枚举类型,因此它也适用于所有数字枚举类型。

答案 1 :(得分:2)

如果你需要这个签名,你仍然可以使它工作 - 你只是不能使用[x..y]枚举 - 一个简单的实现就是这样:

genList :: Num a => Int -> [a]
genList = reverse . genList'

genList' :: Num a => Int -> [a]
genList' 0 = []
genList' n = fromIntegral n : genList' (n-1)

它应该按预期工作:

λ> genList 5 :: [Int]
[1,2,3,4,5]
λ> genList 5 :: [Double]
[1.0,2.0,3.0,4.0,5.0]

答案 2 :(得分:1)

我四处询问。我意识到,我无法理解的是,哈斯克尔不能"演员"任何东西。它只能使类型更具体,如果它之前太一般。

因此1的类型为Num,但通过1 + 1::Int,结果类型变为Int。但它无法从Int返回Num。 所以[1..m_size]的类型为[Int],它比[Num]更具体,而且haskell无法投射它,因为我认为这是因为我习惯使用OO语言。

所以解决这个问题的方法与@Carsten所说的类似。我将首先生成包含Int类型元素的列表,然后重新键入'它以后。所以更精简的解决方案看起来像这样:

genList :: Num a => Int -> [a]
genList n = map fromIntegral [1..n]

有人告诉我,感谢haskell延迟实现,列表元素在被map过程时只会迭代一次。

还要感谢@Ingo @Kiraa @chepner的贡献,我基本上试着在这里总结一下。

答案 3 :(得分:0)

问题不在于将Int重新命名为Num,而是使用[1..m_size]表示法,而不是让a正在实现Enum的编译器放心。函数的类型应为

genList :: (Num t, Enum t) => t -> [t]                                                                                                              

答案 4 :(得分:0)

仅仅因为IntNum的实例并不意味着它等同于任何类型,可以声明为Num的实例。考虑

genList 1000 :: [Int8]

Int8Num的一个实例,但通常Int(特别是在这种情况下,1000)不是Int8类型的值。

假设我们不打算更改函数的定义(请参阅其他答案,了解如何执行此操作),我们可以执行以下两项操作之一:

  1. 将参数类型设置为Int,并意识到我们必须返回Int的列表,因为我们尚未指定创建另一种类型列表的方法。

    genList :: Int -> [Int]
    
  2. 允许使用较少的常规输出类型,该类型指示允许的输入类型。与其他答案类似,ghci可以根据您的定义推断出有效的函数类型:genList :: (Enum t, Num t) => t -> [t]。也就是说,只要输入类型也是[t]并且该类型是t和{{的实例,您就可以为任何类型t返回Enum。 1}}。