I have written a function in Clojure that is supposed to take a logical expression and return an equivalent expression where all not
statements act directly on variables, like so:
(not (and p q r))
becomes
(or (not p) (not q) (not r))
It uses De Morgan's laws to push the not
s inwards, and if a not
acts directly on another not
statement, they cancel out. The code looks like this:
(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
)
)
The problem lies in this part:
(map
transform
(map
not-ify
(rest (first (rest expr)))
)
)
The first map
statement uses a function not-ify
(excuse the pun) to basically put a not
before each statement. That part works. However, the output doesn't work with the map transform
, although the map transform
part works by itself. Let me show you:
If I write the following in the REPL:
(def expr '(not (and q (not (or p (and q (not r)))))))
(map
not-ify
(rest (first (rest expr)))
)
I get the output ((not q) (not (not (or p (and q (not r))))))
If I then take that output and run (map transform '((not q) (not (not (or p (and q (not r)))))))
, I get the output ((not q) (or p (and q (not r))))
. So far so good.
However if I run it all at once, like so:
(map
transform
(map
not-ify
(rest (first (rest expr)))
)
)
I get this output instead: ((not q) (not (not (or p (and q (not r))))))
.
If run
(def test1
(map
not-ify
(rest (first (rest expr)))
)
)
(map transform test1)
I also get ((not q) (not (not (or p (and q (not r))))))
.
However if I run
(def test2 '((not q) (not (not (or p (and q (not r)))))))
(map transform test2)
I once again get the correct result: ((not q) (or p (and q (not r))))
.
My guess is that this is somehow related to the map not-ify
output (test1
) having the type LazySeq
, while if I manually type the input (test2
) it becomes a PersistentList
. I've tried running (into (list))
on test1
to convert it to a PersistentList
, as well as doRun
and doAll
, with no results. Can I somehow stop my map not-ify
statement from returning a LazySeq
?