我正在尝试转换clojure中的逻辑函数。我希望用户能够输入(convert '(and x y z)来产生(nor (nor x) (nor y) (nor z)。因此,我创建了一个带有第一个元素nor的列表,然后尝试创建在执行for循环时创建的其余元素列表。然而,for循环只是将所有列表组合在一起,并将nor保留在列表之外。我还想知道如何跳过列表中的第一个元素,但这不是我现在的首要任务。我对clojure比较陌生,不知道如何返回所有要放入更大列表中的列表。not和or函数与该问题无关。
(defn lookup
"Look up a value, i, in map m and returns the result if it exists.
Otherwise returns i."
[i m]
(get m i i))
(defn makelist
[l]
(for[i[l]] (list 'nor i)))
(defn convert
[l]
(let [p1 (first l)]
(cond
(= p1 'not) (map (fn [i] (lookup i '{not nor})) l)
(= p1 'or) (list 'nor (map(fn [i] (lookup i '{or nor})) l))
(= p1 'and) (list 'nor (makelist l))
:else (print "error"))))我得到的输出是(nor ((nor (and x y z))))。我想要的输出是(nor (nor and) (nor x) (nor y) (nor z)。我也不想要(nor and),但在我弄清楚如何跳过第一个元素之前,我只想把列表分开。
发布于 2019-10-01 09:03:44
我可以看到两个问题:
makelist具有(for [i [l]] ...),因此它只生成一个项目,其中i绑定到整个传入列表l --这里您需要的是(for [i l] ...),以便处理l的每个元素,and的convert's子句创建一个包含两个元素的列表:nor和(makelist l)的结果--您需要的是(cons 'nor (makelist l)),这样您就可以获得一个列表,其中<i>d15是第一个元素,然后是调用makelist.的结果的所有元素
我还没有检查convert的其他两个部分,看看您是否有类似的错误,但是通过上面的两个更改,(convert '(and x y z))将生成(nor (nor and) (nor x) (nor y) (nor z))
发布于 2019-10-01 21:31:50
只是为了好玩:我会在心理上扩展和概括你的任务,根据一些规则重写数据结构,这样你就可以声明(可能是递归的)重写规则,将任何输入转换为任何期望的输出。(并练习clojure)
让我们从简单的转换函数开始:
(defn convert [rules data]
(if-let [res (some (fn [[condition rewrite]]
(when (condition data) (rewrite data)))
rules)]
res
data))它找到适合您的输入的第一个规则(如果有),并应用它的转换函数:
(def my-rules [[sequential? (fn [data] (map #(convert my-rules %) data))]
[number? inc]
[keyword? (comp clojure.string/upper-case name)]])
#'user/my-rules
user> (convert my-rules [:hello :guys "i am" 30 [:congratulate :me]])
;;=> ("HELLO" "GUYS" "i am" 31 ("CONGRATULATE" "ME"))使用这种方法,您的规则将如下所示:
(def rules
[[(every-pred coll? (comp #{'not} first)) (fn [data] (map (partial convert [[#{'not} (constantly 'nor)]]) data))]
[(every-pred coll? (comp #{'or} first)) (fn [data] (map (partial convert [[#{'or} (constantly 'nor)]]) data))]
[(every-pred coll? (comp #{'and} first)) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])
#'user/rules
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))好吧,它可以工作,但看起来相当丑陋。尽管如此,我们仍然可以消除一些重复,为棋盘和转换器引入几个基本功能:
(defn first-is
"returns a function checking that the input is collection and it's head equals to value"
[value]
(every-pred coll? (comp #{value} first)))将您的规则转换为:
(def rules
[[(first-is 'not) (fn [data] (map (partial convert [[#{'not} (constantly 'nor)]]) data))]
[(first-is 'or) (fn [data] (map (partial convert [[#{'or} (constantly 'nor)]]) data))]
[(first-is 'and) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])
#'user/rules
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))然后介绍了替换重写规则:
(defn replacing
([new] [(constantly true) (constantly new)])
([old new] [#{old} (constantly new)])) 引导我们
(def rules
[[(first-is 'not) (fn [data] (map (partial convert [(replacing 'not 'nor)]) data))]
[(first-is 'or) (fn [data] (map (partial convert [(replacing 'or 'nor)]) data))]
[(first-is 'and) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])现在我们可以看到,有一个函数的需求,转换集合中的每一项。让我们来介绍一下它:
(defn convert-each [rules]
(fn [data] (map #(convert rules %) data)))
(def rules
[[(first-is 'not) (convert-each [(replacing 'not 'nor)])]
[(first-is 'or) (convert-each [(replacing 'or 'nor)])]
[(first-is 'and) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])
user> (convert rules '(or x y z))
;;=> (nor x y z)
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))现在它好多了,但最后一个子句仍然有些难看。我可以考虑引入一个函数,它用单独的规则转换头部和尾部,然后协商转换后的头部和尾部:
(defn convert-cons [head-rules tail-conversion]
(fn [[h & t]] (cons (convert head-rules h) (tail-conversion t))))
(defn transforming [transformer]
[(constantly true) transformer])
(def rules
[[(first-is 'not) (convert-each [(replacing 'not 'nor)])]
[(first-is 'or) (convert-each [(replacing 'or 'nor)])]
[(first-is 'and) (convert-cons [(replacing 'nor)]
(convert-each [(transforming #(list 'nor %))]))]])
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))https://stackoverflow.com/questions/58176014
复制相似问题