【问题标题】:Ambiguous type variable `a0' arising from a use of `it'因使用“it”而产生的模棱两可的类型变量“a0”
【发布时间】:2016-11-26 16:10:03
【问题描述】:

我有以下函数来返回给定数字的因子对

factorPairs:: (RealFrac a, Floating a, Integral a) => a -> [(a, a)]
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt n)], n `rem` y == 0]

当我在 ghci factorPairs 18 中调用该函数时,我得到一个运行时错误

   * Ambiguous type variable `a0' arising from a use of `it'
      prevents the constraint `(Floating a0)' from being solved.
      Probable fix: use a type annotation to specify what `a0' should be.
      These potential instances exist:
        instance Floating Double -- Defined in `GHC.Float'
        instance Floating Float -- Defined in `GHC.Float'
    * In the first argument of `print', namely `it'
      In a stmt of an interactive GHCi command: print it

我可以在 ghci 中对函数进行硬编码

map(\x -&gt; (x, div 18 x)) [y | y &lt;- [1..(ceiling $ sqrt 18)], 18 `rem` y == 0] 并且没有任何问题,但我似乎无法弄清楚为什么我的功能失败了。我相信 ghci 试图告诉我它无法确定使用什么类型调用 print,但我正在努力寻找解决方案。

【问题讨论】:

  • 试试 ":t map(\x -> (x, div 18 x)) [y | y rem y = = 0]" 在 GHCi 上找出推断的类型。
  • 你应该重新考虑你的类型签名。你能说出一个既是Floating 又是Integral 的类型吗?我建议您将函数设为单态,例如使用Double,并仅在需要时进行泛化。
  • @ThomasM.DuBuisson 实际上我在想这个是为了好玩:有没有任何 reasonable 类型既是Floating 又是Integral?另外,有没有一种基于实例搜索类型的方法,就像我们可以使用hoogle或hayoo根据类型搜索函数一样?
  • @ThomasM.DuBuisson 我没有声明一个类型签名,然后调用 :t factorPairs。您能否通过使其成为单态来详细说明您的意思。将约束更改为简单的 Double 不会编译
  • 确实,它无法编译。这让您在它起作用之前还有一个步骤,并且会出现一个类型错误,有助于指导查找位置。

标签: haskell functional-programming ghc ghci ambiguous-type-variable


【解决方案1】:

这与 Haskell 中的数字字面量重载有关。当您在ghci 中键入map(\x -&gt; (x, div 18 x)) [y | y &lt;- [1..(ceiling $ sqrt 18)], 18 `rem` y == 0] 时,18(作为sqrt 的参数)默认为Double,其他为Integers。

但是,当你写的时候

factorPairs:: (RealFrac a, Floating a, Integral a) => a -> [(a, a)]
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt n)], n `rem` y == 0]

你强制n 的所有实例只有一种类型。然后,问题就变成了根本没有满足所有这些约束的默认数字类型(实际上我认为通常是数字类型),因此 GHC 会告诉您它尝试的“可能实例”。解决办法是加fromIntegral,放开约束:

factorPairs:: Integral a => a -> [(a, a)]
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt $ fromIntegral n)], n `rem` y == 0]

【讨论】:

    【解决方案2】:

    消除类型错误的另一种方法是消除sqrt 的使用。由于 Haskell 是惰性的,您可以简单地迭代 [1..n],当除数大于商时停止。

    factorPairs :: Integral a => a -> [(a, a)]
    factorPairs n = takeWhile (uncurry (>=)) [ (n `div` d, d) | d <- [1..n], n `mod` d == 0]
    

    uncurry (&gt;=) 只是\(q, d) -&gt; q &gt;= d 的一种写法。

    如果您以单子形式编写此代码,则可以使用 divMod 通过单个函数 all 获取商和余数。

    factorPairs n = takeWhile (uncurry (>=)) $ do
                    d <- [1..n]
                    let (q, r) = n `divMod` d
                    guard $ r == 0
                    return (q, d)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-18
      • 2012-10-18
      • 1970-01-01
      • 2010-09-30
      • 1970-01-01
      相关资源
      最近更新 更多