繁体   English   中英

函数的动态(树)结构作为过程(和Clojure中的实现)

[英]Dynamic (tree) structure of functions as process (and implementation in Clojure)

这听起来可能都很奇怪,因为我无法找到我想要做的确切术语。

我正在开发一个应用程序,给定一组规则(很容易翻译成函数)和输入/输出对(不那么容易翻译成代码),将允许构建一个应用于规则的树的树达到给定输出的给定输入。

它类似于专家系统,除了目标不是确定“更好”(通过某种质量)规则/功能树(实际上映射输入到输出本身是次要的)但是能够根据某些限制或者构建这些树或商业规则。

我试图在Clojure中做到这一点,但我会欣赏更一般的建议,因为我甚至无法弄清楚如何简单地称这种事情。

进入细节,据说我有一个大的平面细节图。 我有一长串功能,我转换为几乎相同:每个函数都采用这个大的平面详细信息图,并将规则应用于此规则所关注的任何值。 函数有副作用(记录它的作用),并且据说是单个布尔输出,由所述(将)树结构用来确定要进入的分支(如果树在此函数上分裂)。

我的想法是我可以使用一个函数并将其声明为树的根。 然后取另一个函数并声明它是下一个要执行的函数,或者取两个函数并根据根函数输出将它们声明为根中的两个下一个分支。 等等等等。 而且我需要能够按照自己的意愿多次进行,生成符合某些要求的树。 我将完成所有的逻辑,但我需要一个结构,允许我应用函数树(我甚至可以构建自己,只要我只需要将它指定为像列表一样简单)到给定输入映射,而不必为我将尝试执行的每个树手动编写整个过程树。

现实生活中的例子是一个大型的树状数据结构(我们可以轻松平放的输入)每个客户端都可以根据他自己的规则集(处理输出时)来描述(函数的副作用) 。

这个“程序”的名称是否比这个长描述更常见? 是否有任何可用于Java / Clojure的功能,或者我应该自己尝试一下? 对于那些了解Clojure的人,我基本上需要一个( - >)系列的变体,它可以采用一个函数树,比如

(tree-> 
input-buffer side-effect-buffer output-buffer (f1 (f2 f4 (f5 f7)) (f3 f6)))

编辑如下:添加示例:这只是我正在寻找的更通用解决方案的一部分:

基于炼金术的(迷你)游戏(更常见的是,真正的化学和炼金术的混合)。 在这种情况下,输入被分组可测量/可观察的混合特征,例如:

(def concoction 
    {:observable {:color {:r 50 :g 50 :b 50} :opacity 50}
     :measurable {:acidity 50 :density 50 :fluidity 50 :composition "TO DO"}
     :testable {:duration 10 :known-effects [list of maps] :safety 10 :after "TO DO"}})

输出是地图的矢量,每个地图类似于:

{:ingredient "ingredient-a" :amount 20 :application {:type "mix" :order 0}}

(独立)功能一般由3部分组成:

  1. 获得混合物的一个(或多个)特征。
  2. 对所选择的特征应用一些受限制的逻辑(来自成分的各个效果的表格中的几个条目,应用类型表或两个或更多成分的组合效果的巨大表格)。
  3. 将处理后的特征记录到共享日志/信息输出中
  4. 将逻辑的应用结果附加到输出。
  5. 返回布尔值(现在,它将是后来的int),表示此步骤在产生输出方面的成功程度。

我改变了一点逻辑,所以现在我只有一个函数将一个给定的逻辑应用于输入(而不是几乎无限量的类似函数),类似于:

(defn apply-logic [input logic-to-apply]
    (let [chalist (apply (:input logic-to-apply) input)
          out (apply (:logic logic-to-apply) chalist)]
     (info-out (apply (:format logic-to-apply) out))
     (return-grade out chalist))))
; info-out uses info-output and output variables set with let somewhere outside

然后我会有一个逻辑树来应用而不是函数:

(def tree-1112 '(logic1 
                 (logic2 
                  (logic3 
                   (logic4 logic5))) 
                 (logic6 
                   (logic7) 
                   (logic8 
                    (logic9)))))

还有一种应用树逻辑:

(defn apply-tree-logic [some-tree input]
 (if (apply-logic input (take-root some-tree)) 
  (apply-tree-logic (take-branch first some-tree) input)
  (apply-tree-logic (take-branch last some-tree) input))

实际上,如果我可以完全按照我在这些示例中提到的那样做,那将非常接近我自己实现它。 但是,我需要花费很多时间来优化所有这些。

听起来你要做的事情在某些方面类似于Plumbing

图表只是从关键字到关键字函数的映射。 在这种情况下,stats-graph表示采用一系列数字(xs)并生成关于这些数字的单变量统计数据的步骤(即,均值m和方差v)。 每个fnk的参数名称可以指在步骤执行之前必须执行的其他步骤。 例如,在上面,要执行:v,您必须首先执行:m和:m2步骤(分别为均值和均值)。

据我所知,你想找到从输入节点到输出节点的图形中的所有路径,其中图形的每个节点都是某个值,每个连接都是函数应用程序,并制作它们的树。

这是一些粗略(和部分)的解决方案:

假设我们想得到一个算术运算列表,以便从另一个数字中得到一个数字。 我们有函数描述:对适用函数的 谓词集合。 谓词检查,如果相应的函数适用于某些输入:

(def fns
  [[zero? {:add3 #(+ 3 %)}]
   [#(== % 1) {:add2 #(+ 2 %) :sub10 #(- 10 %)}]
   [even? {:mul3 #(* 3 %) :add2 #(+ 2 %) :add1 inc}]
   [#(> % 50) {:sub49 #(- % 49)}]
   [(constantly true) {:add1 inc}]])

(defn applicable-fns [fns input]
  (some (fn [[pred f-map]]
          (when (pred input)
            f-map))
        fns))

在repl中:

(applicable-fns fns 1)

;; {:add2 #function[reactive-clj.core/fn--21334], 
    :sub10 #function[reactive-clj.core/fn--21336]}

因为我们无法查看所有数字,所以我们只需将域名限制在-100到100之间:

(defn in-domain? [i] (<= -100 i 100))

现在到函数:clojure有一个很好的机制来遍历树,就像嵌套结构: 拉链

这是一个函数的例子,它将计算从输入到输出的函数链:

(defn get-path [input output next-fns domain-pred]
  (loop [visited #{}
         curr (z/zipper identity
                        #(map (fn [[k v]] [k (v (second %))])
                              (next-fns (second %)))
                        (constantly nil)
                        [nil input])]
    (let [curr-out (-> curr z/node second)]
      (cond (z/end? curr) nil
            (or (visited curr-out) (not (domain-pred curr-out)))
              (recur (conj visited curr) (-> curr z/remove z/next))
            (= output curr-out) (conj (z/path curr) (z/node curr))
            :else (recur (conj visited curr-out)
                         (z/next curr))))))

它是一个简单的qoite(当你看到输入和输出时更容易理解):

(get-path 1 21 (partial applicable-fns fns) in-domain?)
;; => [[nil 1] [:add2 3] [:add1 4] [:mul3 12] [:add2 14] 
       [:add2 16] [:add2 18] [:add2 20] [:add1 21]]

(get-path 51 29 (partial applicable-fns fns) in-domain?)
;; => [[nil 51] [:sub49 2] [:mul3 6] [:mul3 18] [:add2 20] 
       [:add2 22] [:add2 24] [:add2 26] [:add2 28] [:add1 29]]

所以,这些对是深度优先搜索路径的结果。 它不是最短的,但是第一个,这是有效的。 您可以将其读作(-> 1 add2 add1 mul3 .... add1) => 21

如果你真的需要从输入到输出的所有路径,你应该更好地阅读一些带有周期的图形的奇特算法(这可能真的不是一项简单的任务)。 但对我来说最有趣的问题是, 为什么你需要所有的路径,你真的需要它们吗? 你的最终目标是什么? 你将如何使用这个功能树?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM