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

kuw*_*wze 1 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
Run Code Online (Sandbox Code Playgroud)

我收到以下三个错误:

/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.
Run Code Online (Sandbox Code Playgroud)

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

Sil*_*olo 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
Run Code Online (Sandbox Code Playgroud)

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

putStrLn $ "result: " ++ show b
Run Code Online (Sandbox Code Playgroud)

将来,如果您收到的错误看起来令人困惑(例如,您在此处获得的错误为您提供了无用的行号),请尝试使用显式类型签名.例如,如果你想b成为一个整数但是你得到错误,试试吧

let b = (sum $ filter modTest $ [1,2..999]) :: Int
Run Code Online (Sandbox Code Playgroud)

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

  • 为`modTest`添加类型签名也会有所帮助.`modTest :: Int - > Bool`足以推断`b`的类型`Int`. (4认同)
  • 是的,这是为至少为您的顶级函数提供类型的良好实践的原因之一:如果您告诉编译器您的意思,您会得到更好的编译器错误,而不是猜测您的程序的哪个部分是错误的当它发现不一致时. (4认同)