此功能正常:
fromDigits :: [Int] -> Int
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: [Int] -> Int -> [Int]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
但是如果我想从函数中更改类型签名,它就不起作用:
fromDigits :: (Num a) => [a] -> a
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: (Num a) => [a] -> a -> [a]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
这不也不行吗?
答案 0 :(得分:2)
几乎,但不完全。基本问题是length
的类型为[a]->Int
。这将有效:
fromDigits :: Num a => [a] -> a
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: Num b => [b] -> Int -> [b]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
正如Oleg Grenrus指出的那样,应该始终小心检查Int
是否可能溢出。事实上,如果Int
为30,31或32位,则可能会发生这种情况,尽管这种情况相对不太可能发生。但是,如果这是一个问题,可以使用另一个函数来解决它:
lengthIsExactly :: Integral n => n -> [a] -> Bool
lengthIsExactly = -- I'll let you figure this one out.
-- Remember: you can't use `length` here,
-- and `genericLength` is horribly inefficient,
-- and there's a completely different way.
您可以使用GHC扩展程序更轻松地查看fromDigits
和f
的类型如何匹配。通过添加
{-# LANGUAGE ScopedTypeVariables #-}
到源文件的最顶层。然后你可以写
fromDigits :: forall a . Num a => [a] -> a
fromDigits n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: [a] -> Int -> [a]
f n x = if (x==length n) then []
else (10^x):f n (x+1)
这样,很明显列表参数都具有相同的类型。
答案 1 :(得分:2)
问题是你使用的其他功能需要更多的类型而不仅仅是Num a
(^) requires "Integral a"
这有效
fromDigits' :: (Num a, Integral a)=>[a] -> a
fromDigits' n = sum (zipWith (\x y -> x*y) (n) (f n 0))
where
f :: (Num a, Integral a)=>[a] -> a -> [a]
f n x = if (x==fromIntegral (length n)) then []
else (10^x):f n (x+1)