生成范围标准时类型不匹配

时间:2014-01-07 21:40:29

标签: haskell types type-conversion

我正在解决我在互联网上发现的一个有趣的haskell excersize,所以我已经完成了下面的代码,仍然可以通过类型错误重现,但没有透露任何解决方案:

import Control.Monad
import Data.List(permutations)

permutationsUpTo :: Int -> [a] -> [[a]]
permutationsUpTo 0 _ = []
permutationsUpTo _ [] = []
permutationsUpTo n (x:xs) = (permutationsUpTo (n) (xs)) ++ permutations (x:xs)

-- function borrowed from rosetta code
nthRoot n x = fst $ until (uncurry(==)) (\(_,x0) -> (x0,((n-1)*x0+x/x0**(n-1))/n)) (x,x/n)

integerNthRoot n = ceiling . (nthRoot n) . fromIntegral

algorithm :: Int -> Int -> [[Int]]
algorithm x n = do
    perm <- permutationsUpTo x [1..(integerNthRoot n x)]
    guard ((sum perm) == x)
    return perm

当我尝试编译此代码时,我得到:

No instance for (RealFrac Int)
  arising from a use of `integerNthRoot'
Possible fix: add an instance declaration for (RealFrac Int)
In the expression: (integerNthRoot n x)
In the second argument of `permutationsUpTo', namely
  `[1 .. (integerNthRoot n x)]'
In a stmt of a 'do' block:
  perm <- permutationsUpTo x [1 .. (integerNthRoot n x)]

This answer在帮助我了解正在发生的事情方面特别有用,但我似乎无法解决此错误。

提前致谢!

2 个答案:

答案 0 :(得分:2)

问题来自Rosetta Code的代码。如果你检查了GHCi中nthRoot的类型,那就是

nthRoot :: (Eq a, Fractional a) => a -> a -> a

但你真正想要的是

nthRoot :: (Integral a, Eq b, Floating b) => a -> b -> b

如果添加该类型签名,则您的错误来自nxx0之间的算术。一个简单的解决方法:

nthRoot :: (Integral a, Eq b, Floating b) => a -> b -> b
nthRoot n x = fst $ until (uncurry (==)) (\(_, x0) -> (x0, ((n' - 1) * x0 + x / x0 ** (n' - 1)) / n')) (x, x / n')
    where n' = fromIntegral n

然后您的integerNthRoot函数的类型为

integerNthRoot :: (Integral a, Integral b, Integral c) => a -> b -> c

algorithm类型检查。

您应始终将类型签名添加到顶级声明。它会抓住你的错误。


由于Eq b, Floating b中有nthRoot,因此切换为使用Double(由hlint建议)可能更好。那你就是

nthRoot :: Integral a => a -> Double -> Double
nthRoot = ...

我注意到你可能宁愿拥有

integerNthRoot :: (Integral a, Integral b) => a -> b -> b
integerNthRoot = ...

答案 1 :(得分:1)

algorithm的类型签名将n的类型修改为Int,因此您需要nthRoot (fromIntegral n)

(实际上,真的有助于为Haskell中的所有顶层提供类型签名,即使您没有尝试调试类型错误。)