使用sum $ filter'函数'的Haskell错误$ [1,2..999]

时间:2017-12-11 18:44:46

标签: haskell

我试图弄清楚我在以下代码中遇到的多个Haskell错误。这是我的欧拉问题#1的代码:

module Lib
    ( euler1
    ) where

modTest x = mod 3 x == 0 || mod 5 x == 0

euler1 :: IO ()
euler1 = do
  let b = sum $ filter modTest $ [1,2..999]
  putStrLn $ "result: " ++ b

我收到以下三个错误:

/home/kuwze/src/haskell/euler-hs/src/Lib.hs:9:11: error:
    • No instance for (Num [Char]) arising from a use of ‘sum’
    • In the expression: sum $ filter modTest $ [1, 2 .. 999]
      In an equation for ‘b’: b = sum $ filter modTest $ [1, 2 .. 999]
      In the expression:
        do { let b = sum $ filter modTest $ ...;
             putStrLn $ "result: " ++ b }

/home/kuwze/src/haskell/euler-hs/src/Lib.hs:9:24: error:
    • No instance for (Integral [Char]) arising from a use of ‘modTest’
    • In the first argument of ‘filter’, namely ‘modTest’
      In the expression: filter modTest
      In the second argument of ‘($)’, namely
        ‘filter modTest $ [1, 2 .. 999]’

/home/kuwze/src/haskell/euler-hs/src/Lib.hs:9:34: error:
    • No instance for (Enum [Char])
        arising from the arithmetic sequence ‘1, 2 .. 999’
    • In the second argument of ‘($)’, namely ‘[1, 2 .. 999]’
      In the second argument of ‘($)’, namely
        ‘filter modTest $ [1, 2 .. 999]’
      In the expression: sum $ filter modTest $ [1, 2 .. 999] Failed, modules loaded: none.

我知道这是一个简单的问题,但我真的很感激任何帮助。非常感谢你。

1 个答案:

答案 0 :(得分:9)

tl; dr :打印时使用show b

不幸的是,这里的错误不是太大。我会解释它的来源。

module Lib
    ( euler1
    ) where

modTest x = mod 3 x == 0 || mod 5 x == 0

euler1 :: IO ()
euler1 = do
  let b = sum $ filter modTest $ [1,2..999]
  putStrLn $ "result: " ++ b

Haskell会看到你的let b = ...行,并注意到,无论b是什么,它都必须是一些数字的整数类型。那一切都很好;你想要那个。但是你做"result: " ++ b并且Haskell看到b必须是一个字符串。所以它试图合理化这个:字符串是数字类型吗?答案是否定的(除非你定义了一个非常奇怪的实例),这就是为什么你得到Num [Char](或等效Num String)不起作用的错误。您只需要告诉Haskell show您的数值,将其转换为字符串。

putStrLn $ "result: " ++ show b

将来,如果您收到的错误看起来令人困惑(例如,您在此处获得的错误会为您提供无效的行号),请尝试使用显式类型签名。例如,如果您希望b为整数,但是您遇到错误,请尝试

let b = (sum $ filter modTest $ [1,2..999]) :: Int

然后你应该得到更准确的错误信息,因为Haskell更了解你的意图。修复问题后,如果它们使代码混乱,可以删除内联类型注释,但它们对调试非常有帮助。