- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在阅读“Clojure for the Brave and True”在当前章节中,他们正在解释一个程序,该程序采用表示霍比特人 body 部位的散列映射向量。由于包含部件的列表只是不对称地提供(只有左臂、左眼等是其中的一部分),因此有必要编写一个函数来添加相应的右侧部件。后来有一个练习来扩展这个函数,取一个数字,然后为每个剩下的 body 部位加上那个数量的 body 部位。第二个函数会随机选择一个 body 部位。
这是我的代码:
(ns clojure-noob.core
(:gen-class)
(:require [clojure.string :as str] ))
(def asym-hobbit-body-parts [{:name "head" :size 3}
{:name "left-eye" :size 1}
{:name "left-ear" :size 1}
{:name "mouth" :size 1}
{:name "nose" :size 1}
{:name "neck" :size 2}
{:name "left-shoulder" :size 3}
{:name "left-upper-arm" :size 3}
{:name "chest" :size 10}
{:name "back" :size 10}
{:name "left-forearm" :size 3}
{:name "abdomen" :size 6}
{:name "left-kidney" :size 1}
{:name "left-hand" :size 2}
{:name "left-knee" :size 2}
{:name "left-thigh" :size 4}
{:name "left-lower-leg" :size 3}
{:name "left-achilles" :size 1}
{:name "left-foot" :size 2}])
(defn make-sym-parts [asym-set num]
(reduce (fn [sink, {:keys [name size] :as body_part}]
(if (str/starts-with? name "left-")
(into sink [body_part
(for [i (range num)]
{:name (str/replace name #"^left" (str i))
:size size})])
(conj sink body_part)))
[]
asym-set))
(defn rand-part [parts]
(def size-sum (reduce + (map :size parts)))
(def thresh (rand size-sum))
(loop [[current & remaining] parts
sum (:size current)]
(if (> sum thresh)
(:name current)
(recur remaining (+ sum (:size (first remaining)))))))
(defn -main
"I don't do a whole lot ... yet."
[arg]
(cond
(= arg "1") (println (make-sym-parts asym-hobbit-body-parts 3))
(= arg "2") (println (rand-part asym-hobbit-body-parts))
(= arg "3") (println (rand-part (make-sym-parts asym-hobbit-body-parts 3)))))
所以
lein run 1
工作并打印出扩展向量
lein run 2
也可以打印出随机的 body 部位名称。
但是:
lein run 3
会产生以下错误:
861 me@ryzen-tr:~/clojure_practice/clojure-noob$ lein run 3
862 Exception in thread "main" Syntax error compiling at (/tmp/form-init15519101999846500993.clj:1:74).
863 at clojure.lang.Compiler.load(Compiler.java:7647)
864 at clojure.lang.Compiler.loadFile(Compiler.java:7573)
865 at clojure.main$load_script.invokeStatic(main.clj:452)
866 at clojure.main$init_opt.invokeStatic(main.clj:454)
867 at clojure.main$init_opt.invoke(main.clj:454)
868 at clojure.main$initialize.invokeStatic(main.clj:485)
869 at clojure.main$null_opt.invokeStatic(main.clj:519)
870 at clojure.main$null_opt.invoke(main.clj:516)
871 at clojure.main$main.invokeStatic(main.clj:598)
872 at clojure.main$main.doInvoke(main.clj:561)
873 at clojure.lang.RestFn.applyTo(RestFn.java:137)
874 at clojure.lang.Var.applyTo(Var.java:705)
875 at clojure.main.main(main.java:37)
876 Caused by: java.lang.NullPointerException
877 at clojure.lang.Numbers.ops(Numbers.java:1068)
878 at clojure.lang.Numbers.add(Numbers.java:153)
879 at clojure.core$_PLUS_.invokeStatic(core.clj:992)
880 at clojure.core$_PLUS_.invoke(core.clj:984)
881 at clojure.lang.ArrayChunk.reduce(ArrayChunk.java:63)
882 at clojure.core.protocols$fn__8139.invokeStatic(protocols.clj:136)
883 at clojure.core.protocols$fn__8139.invoke(protocols.clj:124)
884 at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
885 at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:27)
886 at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
887 at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
888 at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
889 at clojure.core$reduce.invokeStatic(core.clj:6824)
890 at clojure.core$reduce.invoke(core.clj:6810)
891 at clojure_noob.core$rand_part.invokeStatic(core.clj:39)
892 at clojure_noob.core$rand_part.invoke(core.clj:38)
893 at clojure_noob.core$_main.invokeStatic(core.clj:54)
894 at clojure_noob.core$_main.invoke(core.clj:48)
895 at clojure.lang.Var.invoke(Var.java:384)
896 at user$eval140.invokeStatic(form-init15519101999846500993.clj:1)
897 at user$eval140.invoke(form-init15519101999846500993.clj:1)
898 at clojure.lang.Compiler.eval(Compiler.java:7176)
899 at clojure.lang.Compiler.eval(Compiler.java:7166)
900 at clojure.lang.Compiler.load(Compiler.java:7635)
901 ... 12 more
我一点也不知道为什么会这样。还谷歌搜索错误的第一行不会显示有用的信息。有谁知道这个问题吗?
最佳答案
问题是您返回了一个混合类型的向量。有些元素是映射,有些是列表。注意 make-sym-parts
的前几项:
(make-sym-parts asym-hobbit-body-parts 3)
=>
[{:name "head", :size 3}
{:name "left-eye", :size 1}
({:name "0-eye", :size 1} {:name "1-eye", :size 1} {:name "2-eye", :size 1})
. . .
看看我在这里列出的最后一个条目。这不是 map ;这是一个 map 列表。当您尝试将 :size
应用于列表时,您会得到 nil
:
(:size '({:name "0-eye", :size 1} {:name "1-eye", :size 1} {:name "2-eye", :size 1}))
=> nil
当您将 :size
映射到整个列表时,您会得到:
(->> (make-sym-parts asym-hobbit-body-parts 3)
(map :size))
=> (3 1 nil 1 nil 1 1 2 3 nil 3 nil 10 10 3 nil 6 1 nil 2 nil 2 nil 4 nil 3 nil 1 nil 2 nil)
这会导致问题,因为您通过 reduce
将这些值赋予 +
,如果您给它一个 nil
因为 nil
不是一个数字。
那么,解决办法是什么?老实说,我已经有 3 个月没写 Clojure 了,所以我有点生疏了,我还没有读过问题陈述,但看起来你只需要把这个列表弄平:
(defn make-sym-parts [asym-set num]
(reduce (fn [sink, {:keys [name size] :as body_part}]
(if (str/starts-with? name "left-")
(into sink (conj ; I threw in a call to conj here and rearranged it a bit
(for [i (range num)]
{:name (str/replace name #"^left" (str i))
:size size})
body_part))
(conj sink body_part)))
[]
asym-set))
(make-sym-parts asym-hobbit-body-parts 3)
=>
[{:name "head", :size 3}
{:name "left-eye", :size 1}
{:name "0-eye", :size 1}
{:name "1-eye", :size 1}
{:name "2-eye", :size 1}
{:name "left-ear", :size 1}
{:name "0-ear", :size 1}
{:name "1-ear", :size 1}
{:name "2-ear", :size 1}
{:name "mouth", :size 1}
{:name "nose", :size 1}
{:name "neck", :size 2}
{:name "left-shoulder", :size 3}
{:name "0-shoulder", :size 3}
{:name "1-shoulder", :size 3}
{:name "2-shoulder", :size 3}
{:name "left-upper-arm", :size 3}
{:name "0-upper-arm", :size 3}
{:name "1-upper-arm", :size 3}
{:name "2-upper-arm", :size 3}
{:name "chest", :size 10}
{:name "back", :size 10}
{:name "left-forearm", :size 3}
{:name "0-forearm", :size 3}
{:name "1-forearm", :size 3}
{:name "2-forearm", :size 3}
{:name "abdomen", :size 6}
{:name "left-kidney", :size 1}
{:name "0-kidney", :size 1}
{:name "1-kidney", :size 1}
{:name "2-kidney", :size 1}
{:name "left-hand", :size 2}
{:name "0-hand", :size 2}
{:name "1-hand", :size 2}
{:name "2-hand", :size 2}
{:name "left-knee", :size 2}
{:name "0-knee", :size 2}
{:name "1-knee", :size 2}
{:name "2-knee", :size 2}
{:name "left-thigh", :size 4}
{:name "0-thigh", :size 4}
{:name "1-thigh", :size 4}
{:name "2-thigh", :size 4}
{:name "left-lower-leg", :size 3}
{:name "0-lower-leg", :size 3}
{:name "1-lower-leg", :size 3}
{:name "2-lower-leg", :size 3}
{:name "left-achilles", :size 1}
{:name "0-achilles", :size 1}
{:name "1-achilles", :size 1}
{:name "2-achilles", :size 1}
{:name "left-foot", :size 2}
{:name "0-foot", :size 2}
{:name "1-foot", :size 2}
{:name "2-foot", :size 2}]
在 map
的调用中,您还可以检查元素是 map 还是列表。如果它是一个列表,您可以在子列表上再次调用 (map :size
。这取决于您是想要一个平面列表还是一个嵌套列表作为最终结果。您也可以使用 mapcat
以获得平面列表,尽管这样您就需要处理不是 map 的条目。
您如何从那个(非常冗长的)堆栈跟踪中找出问题所在?一旦您意识到糟糕的解构和糟糕的键查找(就像我上面描述的那样)返回 nil
,推理就会变得容易得多。每当您遇到 NPE 时,立即可以安全地假设您正在解构错误的东西,或者使用错误的 key 进行查找。这些并不是 NPE 的唯一原因,但根据我在 Clojure 中的经验,它们是最常见的。
从上到下读取堆栈跟踪以跟踪不良数据的来源和读取使用的位置。请注意我对如何阅读它的提示的评论:
; If you have an NPE, that means you have a nil being passed somewhere...
Caused by: java.lang.NullPointerException
877 at clojure.lang.Numbers.ops(Numbers.java:1068)
878 at clojure.lang.Numbers.add(Numbers.java:153)
; ... so, you're passing a nil to + ("_PLUS_")
879 at clojure.core$_PLUS_.invokeStatic(core.clj:992)
880 at clojure.core$_PLUS_.invoke(core.clj:984)
881 at clojure.lang.ArrayChunk.reduce(ArrayChunk.java:63)
882 at clojure.core.protocols$fn__8139.invokeStatic(protocols.clj:136)
883 at clojure.core.protocols$fn__8139.invoke(protocols.clj:124)
884 at clojure.core.protocols$fn__8099$G__8094__8108.invoke(protocols.clj:19)
885 at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:27)
886 at clojure.core.protocols$fn__8131.invokeStatic(protocols.clj:75)
887 at clojure.core.protocols$fn__8131.invoke(protocols.clj:75)
888 at clojure.core.protocols$fn__8073$G__8068__8086.invoke(protocols.clj:13)
; ... and it's happening inside a call to reduce
889 at clojure.core$reduce.invokeStatic(core.clj:6824)
; ... and that call to reduce is happening inside of rand-part
891 at clojure_noob.core$rand_part.invokeStatic(core.clj:39)
892 at clojure_noob.core$rand_part.invoke(core.clj:38)
893 at clojure_noob.core$_main.invokeStatic(core.clj:54)
您只有一次这样的 +
实例被传递给 rand-part
内部的 reduce
,所以这是开始寻找的好地方.从那里,您只需要使用标准调试技术跟踪 nil
的来源。
这里的要点是扫描堆栈跟踪以尝试找到您认识的单词。不幸的是,由于 Clojure 名称在翻译成 Java 时会被“破坏”,名称往往非常冗长和嘈杂。你只需要学会“透过噪音看”就能找到相关信息。稍加练习就会变得容易。
其他一些注意事项:
不要在defn
中使用def。 def
创建不受作用域约束的全局变量。请改用 let
。
尝试使用更多的缩进。缩进一个空格不是很好。
Clojure 使用破折号。您在大部分地方都在使用它,但 body_part
似乎是 Python 的倒退。
如果您愿意,可以将此代码发布到 Code Review 上,我们可以提出建议来帮助您改进它。
关于clojure - 非常简单的练习程序无法编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57258829/
我是 C 语言新手,我编写了这个 C 程序,让用户输入一年中的某一天,作为返回,程序将输出月份以及该月的哪一天。该程序运行良好,但我现在想简化该程序。我知道我需要一个循环,但我不知道如何去做。这是程序
我一直在努力找出我的代码有什么问题。这个想法是创建一个小的画图程序,并有红色、绿色、蓝色和清除按钮。我有我能想到的一切让它工作,但无法弄清楚代码有什么问题。程序打开,然后立即关闭。 import ja
我想安装screen,但是接下来我应该做什么? $ brew search screen imgur-screenshot screen
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个简单的 python 客户端程序,它发送消息“hello world how are you”。服务器随后应接收消息,将
我有一个 shell 脚本,它运行一个 Python 程序来预处理一些数据,然后运行一个 R 程序来执行一些长时间运行的任务。我正在学习使用 Docker 并且我一直在运行 FROM r-base:l
在 Linux 中。我有一个 c 程序,它读取一个 2048 字节的文本文件作为输入。我想从 Python 脚本启动 c 程序。我希望 Python 脚本将文本字符串作为参数传递给 c 程序,而不是将
对于一个类,我被要求编写一个 VHDL 程序,该程序接受两个整数输入 A 和 B,并用 A+B 替换 A,用 A-B 替换 B。我编写了以下程序和测试平台。它完成了实现和行为语法检查,但它不会模拟。尽
module Algorithm where import System.Random import Data.Maybe import Data.List type Atom = String ty
我想找到两个以上数字的最小公倍数 求给定N个数的最小公倍数的C++程序 最佳答案 int lcm(int a, int b) { return (a/gcd(a,b))*b; } 对于gcd,请查看
这个程序有错误。谁能解决这个问题? Error is :TempRecord already defines a member called 'this' with the same paramete
当我运行下面的程序时,我在 str1 和 str2 中得到了垃圾值。所以 #include #include #include using namespace std; int main() {
这是我的作业: 一对刚出生的兔子(一公一母)被放在田里。兔子在一个月大时可以交配,因此在第二个月的月底,每对兔子都会生出两对新兔子,然后死去。 注:在第0个月,有0对兔子。第 1 个月,有 1 对兔子
我编写了一个程序,通过对字母使用 switch 命令将十进制字符串转换为十六进制,但是如果我使用 char,该程序无法正常工作!没有 switch 我无法处理 9 以上的数字。我希望你能理解我,因为我
我是 C++ 新手(虽然我有一些 C 语言经验)和 MySQL,我正在尝试制作一个从 MySQL 读取数据库的程序,我一直在关注这个 tutorial但当我尝试“构建”解决方案时出现错误。 (我正在使
仍然是一个初学者,只是尝试使用 swift 中的一些基本函数。 有人能告诉我这段代码有什么问题吗? import UIKit var guessInt: Int var randomNum = arc
我正在用 C++11 编写一个函数,它采用 constant1 + constant2 形式的表达式并将它们折叠起来。 constant1 和 constant2 存储在 std::string 中,
我用 C++ 编写了这段代码,使用运算符重载对 2 个矩阵进行加法和乘法运算。当我执行代码时,它会在第 57 行和第 59 行产生错误,非法结构操作(两行都出现相同的错误)。请解释我的错误。提前致谢:
我是 C++ 的初学者,我想编写一个简单的程序来交换字符串中的两个字符。 例如;我们输入这个字符串:“EXAMPLE”,我们给它交换这两个字符:“E”和“A”,输出应该类似于“AXEMPLA”。 我在
我需要以下代码的帮助: 声明 3 个 double 类型变量,每个代表三角形的三个边中的一个。 提示用户为第一面输入一个值,然后 将用户的输入设置为您创建的代表三角形第一条边的变量。 将最后 2 个步
我是新来的,如果问题不好请见谅 任务:将给定矩阵旋转180度 输入: 1 4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 输出: 16 15 14 13 12 11
我是一名优秀的程序员,十分优秀!