Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 非常简单的练习项目赢得';不编译_Clojure - Fatal编程技术网

Clojure 非常简单的练习项目赢得';不编译

Clojure 非常简单的练习项目赢得';不编译,clojure,Clojure,我现在读的是“Clojure代表勇敢和真实” 在本章中,他们将解释一个程序,该程序采用代表哈比人身体部位的哈希映射向量。由于包含零件的列表只是不对称提供的(只有左臂、左眼等是其中的一部分),因此有必要编写一个函数来添加相应的右零件。后来有一个练习来扩展这个函数,以获取一个数字,并为每个左半身添加该数量的身体部位。第二个函数将随机选择一个身体部位 这是我的代码: (ns clojure-noob.core (:gen-class) (:require [clojure.string :as

我现在读的是“Clojure代表勇敢和真实” 在本章中,他们将解释一个程序,该程序采用代表哈比人身体部位的哈希映射向量。由于包含零件的列表只是不对称提供的(只有左臂、左眼等是其中的一部分),因此有必要编写一个函数来添加相应的右零件。后来有一个练习来扩展这个函数,以获取一个数字,并为每个左半身添加该数量的身体部位。第二个函数将随机选择一个身体部位

这是我的代码:

(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 2
还可以工作并打印出随机的身体部位名称

但是:

将产生以下错误:

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})
  . . .
看看我在这里列出的最后一个条目。这不是一张地图;这是一份地图清单。当您尝试将
: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:size
。这取决于您想要一个平面列表还是一个嵌套列表作为最终结果。您还可以使用
mapcat
来获得平面列表,尽管您需要处理不是映射的条目


那么,如何从(非常详细的)堆栈跟踪中找出问题呢?一旦您意识到错误的解构和错误的键查找(如上文所述)return
nil
,推理就变得容易多了。每当你得到一个NPE时,可以毫不犹豫地假设你在解构错误的东西,或者使用错误的键进行查找。这些不是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\u部分
    似乎是Python的倒退


如果您愿意,您可以将此代码发布在code Review上,我们可以提出建议来帮助您改进。

我认为这是我在Stackoverflow上得到的最有用的答案,谢谢。此外,还提供了有关如何改进代码的信息。我肯定会使用codereview,我还不知道,因此也感谢您:D@Uzaku没问题m、 很高兴能帮上忙。我会看看我以后是否能写一篇评论。如果不是我,我肯定会有其他人参与。我们没有太多的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}]
; 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)