如何解决Haskell中的模糊类型运行时错误?

huangapple go评论68阅读模式
英文:

How can I resolve an ambigious type runtime error in haskell?

问题

我有一个Haskell函数,它计算给定位置的无限列表中的数字:

[2,3,2,4,2,3,2,5,2,3,2,4,2,3,2,...]

因此,对于第n个新数字,列表将是l(n-1) ++ [n] ++ l(n-1)。
我已经实现了这个函数:

getNumb theta = if ((floor (logBase 2 theta)) == ceiling (logBase 2 theta))
              then (floor (logBase 2 theta)) + 2
              else getNumb (2*(floor (logBase 2 theta)) - theta)

但是,当我像这样运行它:getNumb 10 时,我收到了以下错误:

<interactive>:3:1: error:
* Could not deduce (RealFrac t0) arising from a use of `getNumb'
  from the context: Integral p
    bound by the inferred type of it :: Integral p => p
    at <interactive>:3:1-10
  The type variable `t0' is ambiguous
  These potential instances exist:
    instance RealFrac Double -- Defined in `GHC.Float'
    instance RealFrac Float -- Defined in `GHC.Float'
    ...plus one instance involving out-of-scope types
    (use -fprint-potential-instances to see them all)
* In the expression: getNumb 10
  In an equation for `it': it = getNumb 10

<interactive>:3:9: error:
* Could not deduce (Num t0) arising from the literal `10'
  from the context: Integral p
    bound by the inferred type of it :: Integral p => p
    at <interactive>:3:1-10
  The type variable `t0' is ambiguous
  These potential instances exist:
    instance Num Integer -- Defined in `GHC.Num'
    instance Num Double -- Defined in `GHC.Float'
    instance Num Float -- Defined in `GHC.Float'
    ...plus two others
    ...plus two instances involving out-of-scope types
    (use -fprint-potential-instances to see them all)
* In the first argument of `getNumb', namely `10'
  In the expression: getNumb 10
  In an equation for `it': it = getNumb 10

据我理解,问题在于函数的返回类型与输入类型不兼容。这是正确的吗?如果是的话,我该如何修复它?

注意:这是:t的输出,据说返回一个Integer 是正确的。

*Main> :t getNumb
getNumb
  :: (RealFrac t, Floating t, Integral p, Integral t) => t -> p
英文:

I have this haskell function which calculates the number in a given position of this infinite list:

[2,3,2,4,2,3,2,5,2,3,2,4,2,3,2,...]

So for the n-th new number the list would be l(n-1) ++ [n] ++ l(n-1).
I have implemented this function:

getNumb theta = if ((floor (logBase 2 theta)) == ceiling (logBase 2 theta))
              then (floor (logBase 2 theta)) + 2
              else getNumb (2*(floor (logBase 2 theta)) - theta)

but when I run it like this: getNumb 10 I get this error:

&lt;interactive&gt;:3:1: error:
* Could not deduce (RealFrac t0) arising from a use of `getNumb&#39;
  from the context: Integral p
    bound by the inferred type of it :: Integral p =&gt; p
    at &lt;interactive&gt;:3:1-10
  The type variable `t0&#39; is ambiguous
  These potential instances exist:
    instance RealFrac Double -- Defined in `GHC.Float&#39;
    instance RealFrac Float -- Defined in `GHC.Float&#39;
    ...plus one instance involving out-of-scope types
    (use -fprint-potential-instances to see them all)
* In the expression: getNumb 10
  In an equation for `it&#39;: it = getNumb 10

&lt;interactive&gt;:3:9: error:
* Could not deduce (Num t0) arising from the literal `10&#39;
  from the context: Integral p
    bound by the inferred type of it :: Integral p =&gt; p
    at &lt;interactive&gt;:3:1-10
  The type variable `t0&#39; is ambiguous
  These potential instances exist:
    instance Num Integer -- Defined in `GHC.Num&#39;
    instance Num Double -- Defined in `GHC.Float&#39;
    instance Num Float -- Defined in `GHC.Float&#39;
    ...plus two others
    ...plus two instances involving out-of-scope types
    (use -fprint-potential-instances to see them all)
* In the first argument of `getNumb&#39;, namely `10&#39;
  In the expression: getNumb 10
  In an equation for `it&#39;: it = getNumb 10

As far as I understand the problem lies in the return type of the function which is not compatible with the input type. Is this correct? If yes how do I fix it?

Note: This the output of :t and supposedly it is correct to return an Integer

*Main&gt; :t getNumb
getNumb
  :: (RealFrac t, Floating t, Integral p, Integral t) =&gt; t -&gt; p

答案1

得分: 2

计算对数是一种低效的方法来找到这个值。相反,沿着“树”的路径向下工作,并在返回时计算索引。这只需要对参数施加一个Integral约束,因为除了将其除以2之外,你不会做任何其他操作。

请注意,所有偶数索引都计算为2;奇数索引会递归计算。

getNumb theta | even theta = 2
              | otherwise = 1 + getNumb (theta `quot` 2)

even是基于rem实现的,而quotrem都只是quotRem的包装器,所以你可以考虑直接调用quotRem自己。

getNumb theta = case quotRem theta 2 of
                   (_, 0) -> 2
                   (q, _) -> 1 + getNumb q

作为这个方法有效性的证明,注意你可以将这个函数映射到自然数上,以获得原始列表:

> map getNumb [0..30]
[2,3,2,4,2,3,2,5,2,3,2,4,2,3,2,6,2,3,2,4,2,3,2,5,2,3,2,4,2,3,2]
英文:

Computing logarithms is an inefficient way to find the value. Instead, work your way down the "tree", and compute the index on the way back up. This requires only an Integral constraint on the argument, since you never do anything except divide it by 2.

Note that all even indices evaluate to 2; the odd ones are computed recursively.

getNumb theta | even theta = 2
              | otherwise = 1 + getNumb (theta `quot` 2)

even is implemented in terms of rem, and both quot and rem are just wrappers around quotRem, so you might want to simply call quotRem yourself.

getNumb theta = case quotRem theta 2 of
                   (_, 0) -&gt; 2
                   (q, _) -&gt; 1 + getNum q

As proof that this works, note that you can map the function over the natural numbers to get back the original list:

&gt; map getNumb [0..30]
[2,3,2,4,2,3,2,5,2,3,2,4,2,3,2,6,2,3,2,4,2,3,2,5,2,3,2,4,2,3,2]

huangapple
  • 本文由 发表于 2020年1月3日 20:42:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/59578849.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定