Clojure:函数 returns nil 而不是求值表达式
Clojure : function returns nil rather an evaluated expression
我编写了一个对列表成员求和的函数。非常简单,新手的东西,但由于某种原因它 returns 零,我不知道为什么:这应该是一个明智的选择。下面是实现和函数调用。
实施:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 2)
(+ (first x) (first (rest x)) total))
(if (= (count x) 1)
(+ (first x) total))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
函数调用:
(println "our total is: " (add-list-members '(2 23 33 14 33 134 9000 98993)))
与此同时,我有一个添加了打印语句的调试版本,我已经能够验证该实现是否按预期工作。
调试版本:
(defn add-list-members-debug
([x] (add-list-members-debug x 0))
([x total]
(println ">>> our list now: " x)
(println ">>> our total now: " total)
(if (= (count x) 2)
(println "outcome 2 : " (+ (first x) (first (rest x)) total)))
(if (= (count x) 1)
(println "outcome 1 : " (+ (first x) total)))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
调用调试版本:
(add-list-members-debug '(2 23 33 14 33 134 9000 98993))
我使用的开发工具 Vim 已插入 Leiningen REPL。任何关于我在这里做错的提示都将不胜感激。
括号是错误的,或者至少是次优的,并且您没有 returns total
的基本情况。 (关于括号:你的缩进,在给定括号的情况下是正确的,表明:每个 if
都在同一水平上;其中 none 在 "else" 位置。)这是一个正确版本:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 0)
total
(if (= (count x) 2)
(+ (first x) (first (rest x)) total)
(if (= (count x) 1)
(+ (first x) total)
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total))))))))
你得到 nil
作为 return 值,因为当最后一个 if
测试失败时,它会转到 else
子句,在本例中它是一个空的列表的末尾,即 nil
。
不过,多个if
可以用一个cond
代替。您还可以使用 ffirst
代替 (first (first
,使用 fnext
代替 (first (rest
,使用 nnext
代替 (rest (rest
。使用诸如 empty?
之类的谓词而不是检查 count
是否等于 0 也更符合习惯;我使用 count
作为基本案例,只是为了保持与现有代码的并行性。最简单的版本可能是:
(defn add-list-members [x] (apply + x))
您也可以使用 reduce
作为一个非常简单的版本。不过,您可能只是想尝试一下 recur
。
(好吧,你 可以 不使用嵌入的 else
子句,就像你原来的那样,但我不会推荐它,你仍然需要空序列基本情况。当你在函数定义中放置多个单独的表达式时,它们中的每一个都会被执行。这是低效的,而且我觉得容易出错。在函数定义中使用多个单独的表达式是有意义的,当你'重新创建副作用——例如添加用于调试的打印语句。)
你用错了if
。考虑以下代码:我有意简化了代码以清楚说明发生了什么。
(defn xxx [v]
(if (= (count v) 1) "one")
(if (= (count v) 2) "two")
(if (> (count v) 2) "more"))
如果你 运行 (xxx [1])
会怎样?也许您期望代码会 return "one"
,但是,它 returns nil
。为什么?
函数 return 其最后一个表达式的值,在本例中为最后一行 (if (> (count v) 2) "more")
。如果传递 [1]
,第一个 if
表达式 returns "one"
将被忽略。第二个 if
将 return nil
,这也被忽略了。第三个也是最后一个会returnnil
,也就是函数的return值
也许计算元素总和的最简单方法是:
(defn add-elements [xs] (apply + xs))
或
(defn add-elements [xs] (reduce + xs))
您的代码可以用更简单的方式重新实现:
(defn add-elements
([xs] (add-elements xs 0))
([xs total] (if (empty? xs) total
(recur (rest xs) (+ total (first xs))))))
我编写了一个对列表成员求和的函数。非常简单,新手的东西,但由于某种原因它 returns 零,我不知道为什么:这应该是一个明智的选择。下面是实现和函数调用。
实施:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 2)
(+ (first x) (first (rest x)) total))
(if (= (count x) 1)
(+ (first x) total))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
函数调用:
(println "our total is: " (add-list-members '(2 23 33 14 33 134 9000 98993)))
与此同时,我有一个添加了打印语句的调试版本,我已经能够验证该实现是否按预期工作。
调试版本:
(defn add-list-members-debug
([x] (add-list-members-debug x 0))
([x total]
(println ">>> our list now: " x)
(println ">>> our total now: " total)
(if (= (count x) 2)
(println "outcome 2 : " (+ (first x) (first (rest x)) total)))
(if (= (count x) 1)
(println "outcome 1 : " (+ (first x) total)))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
调用调试版本:
(add-list-members-debug '(2 23 33 14 33 134 9000 98993))
我使用的开发工具 Vim 已插入 Leiningen REPL。任何关于我在这里做错的提示都将不胜感激。
括号是错误的,或者至少是次优的,并且您没有 returns total
的基本情况。 (关于括号:你的缩进,在给定括号的情况下是正确的,表明:每个 if
都在同一水平上;其中 none 在 "else" 位置。)这是一个正确版本:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 0)
total
(if (= (count x) 2)
(+ (first x) (first (rest x)) total)
(if (= (count x) 1)
(+ (first x) total)
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total))))))))
你得到 nil
作为 return 值,因为当最后一个 if
测试失败时,它会转到 else
子句,在本例中它是一个空的列表的末尾,即 nil
。
不过,多个if
可以用一个cond
代替。您还可以使用 ffirst
代替 (first (first
,使用 fnext
代替 (first (rest
,使用 nnext
代替 (rest (rest
。使用诸如 empty?
之类的谓词而不是检查 count
是否等于 0 也更符合习惯;我使用 count
作为基本案例,只是为了保持与现有代码的并行性。最简单的版本可能是:
(defn add-list-members [x] (apply + x))
您也可以使用 reduce
作为一个非常简单的版本。不过,您可能只是想尝试一下 recur
。
(好吧,你 可以 不使用嵌入的 else
子句,就像你原来的那样,但我不会推荐它,你仍然需要空序列基本情况。当你在函数定义中放置多个单独的表达式时,它们中的每一个都会被执行。这是低效的,而且我觉得容易出错。在函数定义中使用多个单独的表达式是有意义的,当你'重新创建副作用——例如添加用于调试的打印语句。)
你用错了if
。考虑以下代码:我有意简化了代码以清楚说明发生了什么。
(defn xxx [v]
(if (= (count v) 1) "one")
(if (= (count v) 2) "two")
(if (> (count v) 2) "more"))
如果你 运行 (xxx [1])
会怎样?也许您期望代码会 return "one"
,但是,它 returns nil
。为什么?
函数 return 其最后一个表达式的值,在本例中为最后一行 (if (> (count v) 2) "more")
。如果传递 [1]
,第一个 if
表达式 returns "one"
将被忽略。第二个 if
将 return nil
,这也被忽略了。第三个也是最后一个会returnnil
,也就是函数的return值
也许计算元素总和的最简单方法是:
(defn add-elements [xs] (apply + xs))
或
(defn add-elements [xs] (reduce + xs))
您的代码可以用更简单的方式重新实现:
(defn add-elements
([xs] (add-elements xs 0))
([xs total] (if (empty? xs) total
(recur (rest xs) (+ total (first xs))))))