我正在解决我在互联网上发现的一个有趣的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在帮助我了解正在发生的事情方面特别有用,但我似乎无法解决此错误。
提前致谢!
答案 0 :(得分:2)
问题来自Rosetta Code的代码。如果你检查了GHCi中nthRoot
的类型,那就是
nthRoot :: (Eq a, Fractional a) => a -> a -> a
但你真正想要的是
nthRoot :: (Integral a, Eq b, Floating b) => a -> b -> b
如果添加该类型签名,则您的错误来自n
,x
和x0
之间的算术。一个简单的解决方法:
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中的所有顶层提供类型签名,即使您没有尝试调试类型错误。)