Clojure don';评估不当,似乎与懒散有关
我在Clojure中编写了一个函数,该函数应该接受一个逻辑表达式并返回一个等价的表达式,其中所有Clojure don';评估不当,似乎与懒散有关,clojure,nested,boolean-logic,lazy-sequences,map-function,Clojure,Nested,Boolean Logic,Lazy Sequences,Map Function,我在Clojure中编写了一个函数,该函数应该接受一个逻辑表达式并返回一个等价的表达式,其中所有not语句都直接作用于变量,如下所示: (not (and p q r)) (map transform (map not-ify (rest (first (rest expr))) ) ) 变成 (or (not p) (not q) (not r)) 它使用德摩根定律将nots向内推,如果一个not直接作用于另一个not语句,它们就会
not
语句都直接作用于变量,如下所示:
(not (and p q r))
(map
transform
(map
not-ify
(rest (first (rest expr)))
)
)
变成
(or (not p) (not q) (not r))
它使用德摩根定律将not
s向内推,如果一个not
直接作用于另一个not
语句,它们就会被抵消。代码如下所示:
(defn transform [expr]
(if
(list? expr)
(if
(=
'not
(first expr)
)
(if
(list? (nth expr 1))
(if
(=
'not
(first (nth expr 1))
)
(transform (first (rest (first (rest expr)))))
(if
(=
'and
(first (nth expr 1))
)
(cons
'or
(map
transform
(map
not-ify
(rest (first (rest expr)))
)
)
)
(if
(=
'or
(first (nth expr 1))
)
(cons
'and
(map
transform
(map
not-ify
(rest (first (rest expr)))
)
)
)
expr
)
)
)
expr
)
expr
)
expr
)
)
问题在于这一部分:
(map
transform
(map
not-ify
(rest (first (rest expr)))
)
)
第一个map
语句使用一个函数notify
(请原谅这个双关语),基本上在每个语句之前放置一个not
。那部分有效。但是,输出不适用于映射变换
,尽管映射变换
部分本身可以工作。让我告诉你:
如果我在回复中写下以下内容:
(def expr '(not (and q (not (or p (and q (not r)))))))
(map
not-ify
(rest (first (rest expr)))
)
我得到了输出((非q)(非(或p(和q(非r)俎俎俎俎))
如果我随后获取该输出并运行(map transform'((非q)(非)(或p(和q(和q(不是r))))
,我将得到输出((不是q)(或p(和q(不是r))))
。到目前为止还不错
但是,如果我同时运行它,就像这样:
(not (and p q r))
(map
transform
(map
not-ify
(rest (first (rest expr)))
)
)
我得到的是这样的输出:((不是q)(不是p(或p(和q(不是r))))
如果运行
(def test1
(map
not-ify
(rest (first (rest expr)))
)
)
(map transform test1)
我还得到了((非q)(非(或p)和q(非r‘‘‘‘‘))
但是如果我跑
(def test2 '((not q) (not (not (or p (and q (not r)))))))
(map transform test2)
我再次得到正确的结果:((不是q)(或者p(和q(不是r)))
我的猜测是,这与类型为
LazySeq
的map notify
输出(test1
)有关,而如果我手动键入输入(test2
),它将成为持久列表。我试着在test1
上运行(进入(列表))
,将其转换为PersistentList
,以及doRun
和doAll
,但没有结果。我是否可以阻止我的map notify
语句返回LazySeq
?简单的答案是使用seq?
而不是list?
以下是我将如何实施它:
(defn push-not-down [expr]
(if (and (seq? expr) (seq? (second expr)))
(let [[outer-op & [[inner-op & inner-args] :as outer-args] :as expr] expr]
(if (= 'not outer-op)
(condp = inner-op
'and (cons 'or (map #(push-not-down (list 'not %)) inner-args))
'or (cons 'and (map #(push-not-down (list 'not %)) inner-args))
'not (first inner-args)
expr)
(if (#{'or 'and} outer-op)
(cons outer-op (map push-not-down outer-args))
expr)))
expr))
(deftest push-not-down-test
(testing "Not or and not and are transformed to and not and or not"
(is (= '(or (not :a) (not :b))
(push-not-down
'(not (and :a :b)))))
(is (= '(and (not :a) (not :b))
(push-not-down
'(not (or :a :b))))))
(testing "Double nots cancel"
(is (= :a
(push-not-down
'(not (not :a))))))
(testing "The rules work together in complex combinations"
(is (= '(and :a (and :b (not :c)))
(push-not-down
'(and (not (not :a)) (not (or (not :b) :c))))))
(is (= '(or (or (and (not :a))))
(push-not-down
'(or (or (and (not :a))))))))
(testing "Nested expressions that don't fit the rules are preserved"
(is (= '(not (inc 1))
(push-not-down
'(not (inc 1)))))
(is (= '(inc (or 2 1))
(push-not-down
'(inc (or 2 1)))))))
对于表单和表达式,列表和序列之间没有显著差异。或者,如果您确实想保持倦怠,您只需要更彻底地将序列转换为列表:)为了它的价值
首先,让我们定义逻辑逆是什么:
(def opposite {'and 'or, 'or 'and})
(defn inverse [expr]
(let [default (list 'not expr)]
(if (seq? expr)
(let [[op & args] expr]
(if (= op 'not)
(first args)
(cons (opposite op) (map inverse args))))
default)))
让我们测试一下:
(map inverse ['p '(not p) '(and a b) '(and (not a) b)])
;((not p) p (or (not a) (not b)) (or a (not b)))
它在做这件事的同时,也短路了两个负片
现在我们可以表示转换:
(defn transform [expr]
(if (seq? expr)
(let [[op & args] expr]
(if (= op 'not)
(inverse (first args))
(cons op (map transform args))))
expr))
比如说,
(transform '(not (and p q r)))
;(or (not p) (not q) (not r))
- 当它找到一个
not
时,它返回参数的倒数
- 否则,它将重建表达式,转换
尽可能地使用子表达式,就像
inverse
所做的那样
如果我们不担心转换子表达式,我们可以简化为
(defn transform [expr]
(or (and (seq? expr)
(let [[op & args] expr]
(if (= op 'not) (inverse (first args)))))
expr))
- 我发现拉出
逆操作更容易理解
- 在简单的
转换中
,我玩了和和或和
单臂if
,以避免重复重量较大的不做任何事情的情况
下载OP的文本
这与什么有关
- 我用
seq?
而不是
列表?
- His对未识别的操作抛出异常。我的正好
它们
nil
- 我已经将
和
s和或
s分解为一个案例
map
将始终返回一个lazyseq。您对我如何解决该问题有什么建议吗?不可能有嵌套的map
语句吗?这就是notify
的定义吗?:(defn notify[expr](list'notexpr))
谢谢!这真的帮了我一臂之力。你的例子看起来很棒,不幸的是我对Clojure不是很了解;碰巧我的离散数学课程有Clojure中的计算机作业,没有更多的基础教程,所以你的一半代码在我看来像胡言乱语P