我是函数式语言和clojure的新手,所以请耐心等待......
我正在尝试使用随机参数或常量构造函数列表。构造函数列表的函数已经在工作,但它不会返回函数本身。我使用println验证了这一点。
(编辑:好的,毕竟它还没有正常工作)
(编辑:现在它正在工作,但它不能是“eval”-ed。似乎我需要至少重复两次,以确保至少有两个子节点。这可能吗?)< /强>
以下是摘录:
(def operations (list #(- %1 %2) #(+ %1 %2) #(* %1 %2) #(/ %1 %2)))
(def parameters (list \u \v \w \x \y \z))
(def parameterlistcount 6)
(def paramcount 2)
(def opcount 4)
(defn generate-function
([] (generate-function 2 4 0.5 0.6 () parameters))
([pc maxdepth fp pp function-list params]
(if (and (pos? maxdepth) (< (rand) fp))
(let [function-list
(conj function-list
(nth operations
(rand-int (count operations))))]
(recur pc (dec maxdepth) fp pp function-list params))
(if (and (< (rand) pp) (pos? pc))
(let [ params (pop parameters)
function-list
(conj function-list
(nth params
(rand-int (count params))))]
(if (contains? (set operations) (last function-list) )
(recur (dec pc) maxdepth fp pp function-list params)
nil))
(let [function-list
(conj function-list
(rand-int 100))]
(if (or (pos? maxdepth) (pos? pc))
(if (contains? (set operations) (last function-list) )
(recur pc maxdepth fp pp function-list params)
nil)
function-list))))))
任何帮助将不胜感激,谢谢!
答案 0 :(得分:3)
这是我重写你的功能的注意事项(见下面的评论):
(defn generate-function
([] (generate-function 2 4 0.5 0.6 ()))
([pc maxdepth fp pp function-list]
(if (and (pos? maxdepth) (< (rand) fp))
(let [function-list
(conj function-list
{:op
(nth operations
(rand-int (count operations)))})]
(recur pc (dec maxdepth) fp pp function-list))
(if (and (< (rand) pp) (pos? pc))
(let [function-list
(conj function-list
{:param
(nth parameters
(rand-int (count parameters)))})]
(recur (dec pc) maxdepth fp pp function-list))
(let [function-list
(conj function-list
{:const
(rand-int 100)})]
(if (or (pos? maxdepth) (pos? pc))
(recur pc maxdepth fp pp function-list)
function-list))))))
我的REPL使用的一些例子......
user> (generate-function)
({:const 63} {:op #<user$fn__4557 user$fn__4557@6cbb2d>} {:const 77} {:param \w} {:op #<user$fn__4559 user$fn__4559@8e68bd>} {:const 3} {:param \v} {:const 1} {:const 8} {:op #<user$fn__4559 user$fn__4559@8e68bd>} {:op #<user$fn__4555 user$fn__4555@6f0962>})
user> (generate-function)
({:const 27} {:param \y} {:param \v} {:op #<user$fn__4561 user$fn__4561@10463c3>} {:op #<user$fn__4561 user$fn__4561@10463c3>} {:op #<user$fn__4561 user$fn__4561@10463c3>} {:op #<user$fn__4561 user$fn__4561@10463c3>} {:const 61})
要记住几件事,按照相当随机的顺序:
我在上面使用了recur
来避免在递归自调用中使用堆栈。但是,你有这个dotimes
语句让我想知道你是否有兴趣与一个function-list
调用同时构建一堆generate-function
s。如果是这样的话,使用recur
的尾递归可能不是这样的简单代码的选项,所以你可以选择常规的自调用(但是考虑到达到递归限制的可能性;如果你是积极的,你只会产生小的功能,这不会是一个问题,继续自我调用)或调查继续传递的风格,并以这种风格重写你的功能。
代码中的(do (dec pc) ...)
事件在下一次递归调用中对pc
的值没有任何影响,或者实际上对其当前值没有任何影响。 Clojure中的局部变量(或社区中最常见的局部变量)是不可变的;这包括功能参数。如果你想将递减的pc
传递给某个函数,你就必须这样做,就像你在代码的早期分支中使用maxdepth
一样。
我将你的函数重命名为generate-function
,因为函数名中的驼峰情况在Clojure土地上很不寻常。另外,我将您调用function
的参数重命名为function-list
(所以我应该使用类似generate-function-list
的名称来表示函数... hm),因为这就是它的用途现在
请注意,保持单独的opcount
Var是没有意义的; Clojure的持久列表(由list
函数创建)带有计数,因此(count some-list)
是一个恒定时间操作(并且非常快)。此外,使用operations
和parameters
的向量是不恰当的(并且您可以切换到向量而不更改其余代码中的任何内容!)。例如。 [\u \v \w \x \y \z]
。
在Clojure 1.2中,您可以(rand-nth coll)
使用(nth coll (rand-int (count coll)))
。
如果要从表示ops,params和常量的项目树生成实际的Clojure函数,则需要使用eval
。在大多数情况下都不鼓励这种情况,但不适用于进化编程和类似的东西,这是唯一的方法。
就个人而言,我会使用不同格式的op / param / constant地图:{:category foo, :content bar}
foo
为:op
,:param
或:const
和bar
与任何给定的foo
相关。
答案 1 :(得分:2)
一般来说,在Clojure中使用(recur ...)作为递归函数是一个更好的主意。从文档:“请注意,recur是Clojure中唯一不占用堆栈的循环结构。” link
另外需要注意的是,您可能希望在递归函数之外调用随机函数,因此您可以在函数内定义停止条件。
所以这样:
(let [n (rand-int 10)]
(println "Let's define f with n =" n)
(defn f [x]
(if (> x n)
"result"
(do (println x)
(recur (inc x))))))
打印:
Let's define f with n = 4
user> (f 0)
0
1
2
3
4
"result"
其中4当然是0(含)和10(不含)之间的随机数。
答案 2 :(得分:1)
好吧,我发现我的方式错了。 树的递归定义不仅仅是定义顶点,而是尝试将所有内容与之绑定在一起。所以,我在不到15分钟的时间内想到了这一点。 &GT; _&LT;
(defn generate-branch
"Generate branches for tree"
([] (generate-branch 0.6 () (list \x \y \z)))
([pp branch params]
(loop [branch
(conj branch (nth operations (rand-int (count operations))))]
(if (= (count branch) 3)
branch
(if (and (< (rand) pp))
(recur (conj branch (nth params (rand-int (count params)))))
(recur (conj branch (rand-int 100))))))))
(defn build-vertex
"Generates a vertex from branches"
[]
(let [vertex (list (nth operations (rand-int (count operations))))]
(conj vertex (take 5 (repeatedly generate-branch)))))
感谢每个人!