全局变量“total”未正确更新

Global Variable “total” Does Not Update Properly

我正在做一项计算列表中所有整数之和的作业。除了标准加法运算符 .

之外,我应该 在没有任何标准库函数帮助的情况下这样做

我想这意味着我不能使用 length我的理解是正确的,对吗? 这成为问题,因为我不确定我如何知道何时停止我的递归函数以遍历数组。

预期要处理的输入 a 是 [][0-X],其中 x 是任何整数。该示例的 X 为 10,所以不要期望测试任何大的东西。

作业提到它应该采用以下格式,但我不确定是否遵循:

sum1 []     = ...
sum1 (x:xs) = ...

这是我使用的长度。它工作正常,我真的不在乎它是否低效。这是我第一次使用 Haskell:

iterate_list :: [Int] -> Int -> Int -> IO()
iterate_list func_list index total = do
    if index < length func_list
    then do
        let new_total = total + (func_list !! index)
        let new_index = index + 1
        iterate_list func_list new_index new_total
    else 
        print(total)
        

sum1 :: [Int] -> IO()
sum1 list = do
    if length list < 1
    then do
        print(0)
    else
        iterate_list list 0 0

更新: 根据评论,这是我生成的代码。

total :: Int
total = 0

sum1 :: [Int] -> IO()
sum1 (x:xs) = do
    if xs == []
    then do
        print(total)
    else do
        let total = total + x
        sum1 xs

但是,我现在遇到的问题是 total returns 0,几乎就像是一个常数。我可能是这样编程的,但我不太确定发生了什么。

根据赋值说明,我不能通过递归函数传递一个变量来存储这个值。我以前也这样做过。有谁知道是否有办法在函数之外有一个“total”变量。

total :: Int
total = 0

sum1 :: [Int] -> IO()
sum1 (x:xs) = do
    if xs == []
    then do
        print(total)
    else do
        let total = total + x
        sum1 xs

这段代码的内容:

  • 全局total是一个常数整数,等于0

  • sum1 接受一个整数列表并产生一个不产生任何结果的 IO 动作

  • 如果给sum1一个非空列表,那么:

    • 如果该列表的尾部为空(即整个列表有 1 个元素),则打印全局变量 total

    • 否则:

      • 新建一个新的局部变量,命名为total,隐藏全局变量,定义为x加上自身(一个无限循环)

      • 在列表的尾部递归调用sum1

  • 如果给sum1一个空列表,它会抛出一个错误

这表明您的思考非常迫切。与其尝试定义一个自下而上的 过程 来逐步更新总数,直到它 累积 到最终结果,您需要从以下方面进行思考如何通过 分解 输入来计算总计值。 Haskell中的变量是不可变的;当你写 = 时,它意味着 等于 ,永远不要“分配”或“更新”。

首先,sum1 应该 return Int 因为你不需要 IOdo 符号。

sum1 :: [Int] -> Int

如果要打印应用于某些列表 someListsum1 的结果(例如来自 main),请在此处使用 print,即 print (sum1 someList).

接下来,应根据输入的两种可能情况定义函数:空列表和非空列表。

sum1 [] = …

sum1 (x : xs) = …

您需要定义这些情况,以便您会记得像 sum1 [1, 2, 3, 4] 这样的输入是 sum1 (1 : (2 : (3 : (4 : []))))syntactic sugar 产生等同于 1 + 2 + 3 + 4 的内容。

首先,在空列表的情况下,结果应该是什么?您可以从以下事实中推断出这一点:附加在一起的两个列表的总和应该与它们各自的总和相同;也就是说,对于任何列表 xsys,这些表达式应该产生相同的结果:

sum1 xs + sum1 ys
sum1 (xs ++ ys)

假设xsys为空,则不应改变和:

  • sum1 [] + sum1 ys = sum1 ([] ++ ys) = sum1 ys
  • sum1 xs + sum1 [] = sum1 (xs ++ []) = sum1 xs

其次,对于非空情况:给定一个元素x :: Int和一个列表xs :: [Int],您需要计算两者的总和。例如,给定 [1, 2, 3, 4]x 设置为 1,而 xs 设置为 [2, 3, 4]。假设您已经有了 xs 的总和;那个和 x 的结果是什么?以及如何获得 xs?

的总和

不能简单地更新Haskell中的变量。所有的值都是不可变的。您应该考虑如何使用递归调用的 return 值,而不是简单地调用一个函数来产生副作用。

您最初问题的提示是定义

sum [] = ...
sum (x:xs) = ...

首先,非空列表的总和是多少?它必须包含 x,因此您需要向 x 添加内容:

sum (x:xs) = x + ...

第二,一个空列表求和是多少?虽然甚至 定义 一个空列表的值可能没有意义,但想想 sum [3] 肯定 return,以及 sum (3:[]) == 3 + .... sum [] 有一个相当简单的定义,几乎由加法的定义决定。