1

当我学习clojure时,我正在尝试构建一个简单的井字游戏,没有ia。我开始使用一种方法来显示板,但它对我来说似乎很丑:我正在使用内部函数,以便使它们成为 show-board 方法的本地函数,这样它就不能在外部实例化。也许是长得不好的原因。

这是功能(按我的意愿工作):

(defn show-board [board]
    "Prints the board on the screen.
     Board must be a list of three lists of three elements with
     :cross for a cross and :circle for a circle, other value for nothing"
    (let [convert-elem (fn [elem] 
                            (cond
                                    (= elem :cross) "X"
                                    (= elem :circle) "O"
                                    :other "_"))
          convert-line (fn [elems-line]
                            (reduce str (map convert-elem elems-line)))]
         (doseq [line board]
            (println (convert-line line)))))

这是一个用例:

(show-board (list (list :cross :circle :none) (list :none :circle :none) (list :cross :none :none)))

对不起,丑陋的代码,这是因为我来自 Java,我是从 Clojure 开始的。(我想我真的会从学习 Clojure 中受益,并用它制作游戏,所以我不能就这样离开它)。

我想简化它的另一个原因是代码维护和可读性。

提前致谢

4

3 回答 3

2

使用内部函数非常好,尽管在这种情况下使用letfn可能看起来更好。此外,convert-elem可以简化case并且convert-line应该使用apply,而不是reduce出于我在对Clojure的回答中解释的原因:reduce vs. apply SO 问题(简而言之,使用单个并且结果过程是线性的;使用,每个步骤都涉及分配一个新的,过程是二次的;像这样的小案例并没有太大的区别,但使用正确的方法仍然是更好的风格)。applyStringBuilderreduceStringBuilder

这是修改后的功能:

(defn show-board [board]
  "Prints the board on the screen.
   Board must be a list of three lists of three elements with
   :cross for a cross and :circle for a circle, other value for
   nothing."
  (letfn [(convert-elem [elem] 
            (case elem
              :cross "X"
              :circle "O"
              "_"))
          (convert-line [elems-line]
            (apply str (map convert-elem elems-line)))]
    (doseq [line board]
      (println (convert-line line)))))

附带说明一下,此函数实际上采用任意 seqable 的 seqable,不一定是列表的列表。Clojure 中更常见的具体类型选择是使用向量:

user> (show-board [[:cross :circle :none]
                   [:none :circle :none]
                   [:cross :none :none]])
XO_
_O_
X__
nil
于 2013-08-21T21:45:50.883 回答
2
(defn show-board
  [board]
  (let [convert (fn [el] (get {:cross \X :circle \O} el \_))]
    (doseq [line board]
      (doseq [el line]
        (print (convert el)))
      (println))))
于 2013-08-21T22:46:57.910 回答
2

简单地让底层编写器缓冲输出而不是创建中间字符串(即使您通过 a 创建它们StringBuilder)怎么样?

=> (defn show-board [board]
     (doseq [line board]
       (doseq [item line]
         (print ({:cross \X :circle \O} item \_)))
       (newline)))

如果你想得到一个字符串而不是打印出来,只需使用with-out-str.

于 2013-08-22T09:51:40.923 回答