【问题标题】:How to solve the ambiguous type variable error in Haskell如何解决 Haskell 中不明确的类型变量错误
【发布时间】:2020-07-08 00:15:10
【问题描述】:

我想实现以下函数来计算 Julia 中整数 $n$ 的 $(-1)^n / (2n + 1)$ 到 Haskell 中。

# Julia

powersign(n) = ifelse(n % 2 == 0, 1, -1)

leibniz_term(n) = powersign(n) / (2n + 1)

println(leibniz_term(10)) # 0.047619047619047616

我写

-- Haskell

powersign 0 = 1
powersign 1 = -1
powersign n = powersign (rem n 2)

leibniz_term n = (powersign n) / (2 * n + 1)

main = print (leibniz_term 10)

但这会产生以下错误。

$ ghc -o leibniz_hs leibniz.hs
[1 of 1] Compiling Main             ( leibniz.hs, leibniz.o )

leibniz.hs:9:8: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘print’
      prevents the constraint ‘(Show a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
        ...plus 22 others
        ...plus 13 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: print (leibniz_term 10)
      In an equation for ‘main’: main = print (leibniz_term 10)
  |
9 | main = print (leibniz_term 10)
  |        ^^^^^^^^^^^^^^^^^^^^^^^
...

可能,我需要在某处添加类型注释,但我不知道该怎么做。 如何修改代码才能正常工作?

【问题讨论】:

  • 建议为每个定义提供一个类型签名——这将产生更好的错误消息。另外,打开警告,并尽量尊重它们。

标签: haskell


【解决方案1】:

请注意,rem 适用于类似Integer 的数字,因此应将powersign 应用于这些数字(在名为Integral 的haskell 类型类中)。而除法(/) 是实数除法。编译器无法知道leibniz_term 中的n 是类整数还是类实数。在 haskell 中,您应该显式地在数字类型之间进行转换。

powersign 0 = 1
powersign 1 = -1
powersign n = powersign (rem n 2)

leibniz_term n = fromIntegral (powersign n) / (2 * fromIntegral n + 1)

main = print (leibniz_term 10)

Haskell 的数值层次结构不完整的历史

在 haskell 中,您有常规数字类型:IntIntegerFloatDouble

它们都实例化了Num 类型类。这意味着他们可以执行

(+), (-), (*), signum, negate, ... (and some others)

那么除法不同,你有Integral类型类来执行整数除法:quot, rem, etc...。该类型类的成员为IntInteger

Fractional 类型类执行实数除法:/。该类型类的成员为FloatDouble

要执行cossinlog 等数学运算...您拥有Floating 类型类,其成员为FloatDouble

强制是通过fromIntegral 完成的,它将IntInteger 转换为任何其他数字类型。从DoubleFloat 转换回Integral 是使用常见的truncateceiling 等完成的......

您还有另一种数字类型,称为Rational,它实际上是Intergers 之间的比例。还有一些其他的数字类,如RealFracRealFloat。您可以在此处获取更多信息:https://wiki.haskell.org/Converting_numbershttps://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html

【讨论】:

  • 所以/ 对于整数(它们是实数)不是实数除法(在 Julia 中)而是整数商(在 Haskell 中)?
  • @Paalon 没有。未为整数定义运算符 /。如果你在 GHCi 中输入:t (/),你会看到类型签名是(/) :: Fractional a => a -> a -> a,这意味着/ 是为实现Fractional 类型类的类型定义的。如果你输入:i Int,你会看到IntInteger 都有Fractional 实例。让我编辑问题,以添加有关此的更多信息
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多