【问题标题】:type error when creating list from integral type从整数类型创建列表时出现类型错误
【发布时间】:2019-03-31 07:44:38
【问题描述】:

我正在尝试实现一个简单的功能:totient:

coprime :: Integral a => a -> a -> Bool
coprime a b = gcd a b == 1

totient :: Integral a => a -> a
totient m = length $ filter (coprime m) [1..m-1]

ghci> :load 99problems.hs
[1 of 1] Compiling Main             ( 99problems.hs, interpreted )

99problems.hs:250:13: error:
    • Couldn't match expected type ‘a’ with actual type ‘Int’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          totient :: forall a. Integral a => a -> a
        at 99problems.hs:249:12
    • In the expression: length $ filter (coprime m) [1 .. m - 1]
      In an equation for ‘totient’:
          totient m = length $ filter (coprime m) [1 .. m - 1]
    • Relevant bindings include
        m :: a (bound at 99problems.hs:250:9)
        totient :: a -> a (bound at 99problems.hs:250:1)
Failed, modules loaded: none.

我尝试在(m-1) 上使用fromIntegraltoInteger 之类的东西,但都没有奏效。我不确定我在这里缺少什么......似乎Int 应该是Integral a => a 类型。怎么了?

【问题讨论】:

  • length 的类型是length :: Foldable t => t a -> Int。但是您明确表示totient 应该返回Integral a
  • 正如答案所解释的,fromIntegral (Num b, Integral a) => A -> b 意味着调用者(length 函数)需要为其提供任何Integral aInt 是一个 Integral 所以这检查出来了。然后,fromIntegral 返回一个Num b,用户(totient 函数)选择它的类型。在这种情况下,您在类型声明中选择它为 Integral
  • 注意,当你“选择”返回的类型时,你不需要限制它,在这种情况下你可以返回Num b,它仍然有效。
  • 您也可以使用genericLength(来自Data.List)而不是length 来修复它。 length 的返回类型是单态的,这可能很烦人,这似乎是标准库的初始设计中的一个错误,我们希望在未来的版本中进行更改。
  • 但是fromIntegral 正在返回一个通用的Num 类型,然后你选择你想要的类型。您可以按原样离开,也可以像您正在做的那样将其“投射”到Integral

标签: haskell integer


【解决方案1】:

类型Integral a => a -> a 说:

  1. 来电者可以选择类型a
  2. 调用者必须证明aIntegral 的一个实例。
  3. 调用者必须提供a类型的值。
  4. 实现者产生另一个a类型的值。

但是,在这种情况下,实施者生成了一个Int。任何时候调用者选择a 作为Integral 的实例,而不是Int,这将与调用者的类型不匹配。

【讨论】:

    猜你喜欢
    • 2013-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-18
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 2021-02-19
    相关资源
    最近更新 更多