我正在写一个遗传算法。为了帮助在运行时使用设置,我试图将设置(突变率,交叉机会,适应度函数......)保存到磁盘。这将允许我修改文件,然后偶尔读取文件以在运行时更新设置。从控制台获取输入会更容易,但Intellij输入输入的能力非常糟糕,并且证明使用起来太难了,所以这就是我正在尝试的路线。
我的问题是:设置由记录表示。许多单独的设置都是数字,因此很容易保存到磁盘。但是有些设置是功能,不能很好地保存:
(defrecord Settings [
gene-set
sequence-length
fitness-f])
(with-out-str (pr
(->Settings #{1 2 3}
10
#(count %)))))
收率:
"#ai.genetic_algorithm.genetic_algorithm2_2.Settings{:gene-set #{1 3 2}, :sequence-length 10, :fitness-f #object[ai.genetic_algorithm.genetic_algorithm2_2$eval776$fn__777$fn__778 0x1b30c92 \"ai.genetic_algorithm.genetic_algorithm2_2$eval776$fn__777$fn__778@1b30c92\"]}"
在大多数情况下,除了表示适应度函数的方式外,这很好。如果我尝试重新阅读该文件:
(read-string
(with-out-str (pr
(->Settings #{1 2 3}
10
#(count %)))))
我明白了:
ai.genetic-algorithm.genetic-algorithm2-2=> RuntimeException No reader function for tag object clojure.lang.LispReader$CtorReader.readTagged (LispReader.java:1245)
我在尝试保存/读取函数时只收到此错误。我猜它无法知道我要求它读取函数,所以它是barfs。
有没有办法可靠地将匿名函数保存到文件?
是的,我知道read-string
有潜在危险。我只是将它用于个人项目,所以我并不担心这个漏洞。
答案 0 :(得分:0)
如果更改代码而不是生成函数,然后从命名空间中提取该函数以将其保存到文件,则需要生成设置的表达式并将表达式保存到文件中。然后使用加载该文件的结果作为新状态。
user> (let [new-config '{:gene-set #{1 2 3}
:sequence-length 10
:fitness-f (fn [x] (count x))}]
(with-open [w (clojure.java.io/writer "/tmp/config.edn")]
(binding [*out* w]
(pr new-config)))
(load-file "/tmp/config.edn"))
{:gene-set #{1 3 2},
:sequence-length 10,
:fitness-f #function[user/eval111126/fn--111127]}
当您定义要保存的新适应度函数时,将其生成为符号序列,并在将序列编译为函数类之前保存该序列。让它编译的唯一时间是它被加载,所以你知道它将永远是可加载的东西。这将抓住错误。
如果您发现自己想要机械地生成这些组合,您可能需要考虑给它们命名,只保存配置中的组合顺序。