Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure don';评估不当,似乎与懒散有关_Clojure_Nested_Boolean Logic_Lazy Sequences_Map Function - Fatal编程技术网

Clojure don';评估不当,似乎与懒散有关

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语句,它们就会

我在Clojure中编写了一个函数,该函数应该接受一个逻辑表达式并返回一个等价的表达式,其中所有
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