没有因使用“和”而产生的(Num a)实例 - 实例数量

时间:2015-01-24 20:20:59

标签: haskell

此功能正常:

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)

这不也不行吗?

2 个答案:

答案 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扩展程序更轻松地查看fromDigitsf的类型如何匹配。通过添加

启用扩展程序
{-# 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)