第一个Haskell函数写作问题

3

我刚接触Haskell,但我的代码无法编译。

multipleSum :: Int -> Int
multipleSum x = let recSum 0 b = b
                    recSum a b | a mod 3 == 0     = recSum a-1 b+a
                               | a mod 5 == 0     = recSum a-1 b+a
                               | otherwise        = recSum a-1 b
                in recSum x 0 

我遇到了两个错误,第一个出现在第3行,第二个出现在第6行。我做错了什么?(这个函数应该是小于n的所有3和5的倍数之和)

1.
Occurs check: cannot construct the infinite type: a ~ a -> a -> a
Expected type: (a -> a -> a) -> a -> a
  Actual type: ((a -> a -> a) -> a -> a) -> (a -> a -> a) -> a -> a
Relevant bindings include
  b :: (a -> a -> a) -> a -> a
    (bound at src\Main.hs:5:30)
  a :: (a -> a -> a) -> a -> a
    (bound at src\Main.hs:5:28)
  recSum :: ((a -> a -> a) -> a -> a)
            -> ((a -> a -> a) -> a -> a) -> (a -> a -> a) -> a -> a
    (bound at src\Main.hs:4:21)
In the first argument of `(-)', namely `recSum a'
In the first argument of `(+)', namely `recSum a - 1 b'


2.Couldn't match expected type `(a0 -> a0 -> a0) -> a0 -> a0'
            with actual type `Int'
In the first argument of `recSum', namely `x'
In the expression: recSum x 0

Couldn't match expected type `Int'
            with actual type `(a0 -> a0 -> a0) -> a0 -> a0'
Probable cause: `recSum' is applied to too few arguments
In the expression: recSum x 0
In the expression:
  let
    recSum 0 b = b
    recSum a b
      | a mod 3 == 0 = recSum a - 1 b + a
      | a mod 5 == 0 = recSum a - 1 b + a
      | otherwise = recSum a - 1 b
  in recSum x 0
2个回答

8
您有两个与语法相关的问题。第一个问题涉及到函数和运算符优先级。在Haskell中,函数应用具有最高的优先级,因此recSum a-1 b+a被视为与(recSum a)-(1 b)+a相同。您需要写成recSum (a-1) (b+a)
第二个问题是a mod 3是调用带有参数mod3的函数a。要将mod用作中缀运算符,请将其写为
a `mod` 3

将这两个变化结合起来,我们会得到:
multipleSum :: Int -> Int
multipleSum x = let recSum 0 b = b
                    recSum a b | a `mod` 3 == 0  = recSum (a-1) (b+a)
                               | a `mod` 5 == 0  = recSum (a-1) (b+a)
                               | otherwise       = recSum (a-1) b
                in recSum x 0 

7

首先,如果您能够获取更多类型签名,则更容易进行调试,因此我会将其重写为:

multipleSum :: Int -> Int
multipleSum x = recSum x 0

recSum :: Int -> Int -> Int
recSum 0 b = b
recSum a b | a mod 3 == 0     = recSum a-1 b+a
           | a mod 5 == 0     = recSum a-1 b+a
           | otherwise        = recSum a-1 b

在ghci或hugs中运行它。

这样我会得到关于a mod 3的错误。

好的,我必须使用反引号编写中缀函数,所以应该是

recSum :: Int -> Int -> Int
recSum 0 b = b
recSum a b | a `mod` 3 == 0     = recSum a-1 b+a
           | a `mod` 5 == 0     = recSum a-1 b+a
           | otherwise        = recSum a-1 b

现在我遇到了有关recSum a-1 b+a参数数量的错误。 这是因为只应该有两个参数,所以如果我要传递比单个变量更复杂的内容,就需要括号,因此我应该写成

recSum :: Int -> Int -> Int
recSum 0 b = b
recSum a b | a `mod` 3 == 0     = recSum (a-1) (b+a)
           | a `mod` 5 == 0     = recSum (a-1) (b+a)
           | otherwise        = recSum (a-1) b -- don't need brackets for b on its own

现在已经编译完成,是时候使用各种输入来测试它,看它是否按照预期工作了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接