首页 > 解决方案 > 如何解决 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

标签: haskelltypes

解决方案


计算对数是一种低效的求值方法。相反,沿着“树”向下工作,并在备份的路上计算索引。这仅需要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 + getNum 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]

推荐阅读