I want to create an || comparison with Clojure like other languages.
(defmacro ||
[source & other]
`(loop [s# [~source ~#other]]
(println s#)
(let [fs# (first s#)]
(if fs#
fs#
(if (= (count s#) 1)
fs#
(recur (next s#)))))))
but this can't work. fs# value is quote data.
like this
(def a [1])
(defn b []
(println 11111))
(|| (get a 0) (b))
I want the result to be 1, this is (get a 0) but the result is (get a 0) this is Expression, not a var. How do I create an || macro?
Clojure's equivalent of || is the macro or . You can view its implementation here.
If you want to use the symbol ||, you can just alias the or macro:
(def #^{:macro true} || #'or)
You can then use either:
(or (get a 0) (b))
or
(|| (get a 0) (b))
What's your expected result, (get a 0) or 1? On my machine ,the result of your code is 1. I think that's nothing to do with macros. Before expanding the macro (|| (get a 0) (b)), (get a 0) and (b) will be evaluated and the macro just get arguments 1 and nil. If you want result of (get a 0), you should use (|| '(get a 0) (b))
Related
As I've come to know it, the form of an if is (if [condition] [true] [false]). Similarly, cond is (cond [condition] [true] ... [condition] [true] [false]). Each true and false segment seems to only accept one action. If I want to represent the following logic:
if (i > 0)
{
a += 5;
b += 10;
}
I think I have to do:
(if (> i 0) (def a (+ a 5)))
(if (> i 0) (def b (+ b 10)))
Just so the second action isn't confused as a false result. Is this how it needs to be, or is there a way to create a larger body for an if?
p.s. I also suspect redefining a and b each time isn't the best way to increment, but also haven't seen a different way of doing that. I've had to also redefine lists when using conj.
The most direct transaction, using atoms instead of vars (def), would be
;; assuming something like (def a (atom 0)) (def b (atom 0))
(if (> i 0)
(do
(swap! a + 5)
(swap! b + 10)))
or
(when (> i 0)
(swap! a + 5)
(swap! b + 10))
You are looking through the wrong end of the telescope. Bear in mind that
Clojure has no local variables.
Clojure has no actions (usually called statements), only expressions returning a value.
There is no Clojure equivalent of the statement a += 5;.
However, expressions can have side effects: print and the like accomplish nothing else. The do form allows you to accomplish a series of side effects before returning a final value. For example,
(do (print a) (print b) (+ a b))
prints a,
prints b,
returns their sum.
That's why, as you write of the if form ...
Each true and false segment seems to only accept one action.
What Clojure does have is
local name bindings, with the let form and
a derived version of let called loop that implements a primitive
form of recursion that can replace simple uses of loops in
languages like C or Java.
Between them, let and its offspring loop allow you to write most simple control structures. to determine if this applies to your program fragment ...
if (i > 0)
{
a += 5;
b += 10;
}
... we'd have to see the context.
However, here's a greatest common divisor function in C (untested)
long gcd (long i, long j)
{
long m = i, n = j;
while (n != 0)
{
long t = n;
n = m % n;
m = t;
}
}
and in Clojure
(defn gcd [i j]
(loop [m i, n j]
(if (zero? n)
m
(recur n (mod m n)))))
Both of these can be abbreviated.
The other answer covered the explicit question about having more than one expression in the if branch (using do or by using when if there is no else branch as when wraps its nested expressions implicit do).
However, there is another issue in the question with using state which is usually local to the function. I don't think an atom stored in a global var is the best way to handle that, and as Clojure programs tend to minimise global state it's usually better to keep the state local.
We use let to define the local state and narrow its scope (NB it also supports destructuring):
(let [i 0
a 5
b 10]
(println i)
(println a)
(println b))
let assigns a value to a local variable and it cannot be redefined. If we need to update local state we can use recursion by calling recur directly on the function or by using loop and recur.
For example:
(defn plus [a b]
(if (> b 0)
(do
(println "Recurring...")
(recur (inc a) (dec b)))
(do
(println "Returning result")
a)))
Or:
(defn plus [a b]
(loop [a a
b b]
(if (> b 0)
(do
(println "Recurring...")
(recur (inc a) (dec b)))
(do
(println "Returning result")
a))))
(> 1 (first [])) returns NullPointerException.
How can I make (first []) return a default value, such as 0, instead of nil?
You can use or to bypass the nil value
(> 1 (or (first []) 0))
Because in Clojure, nil is treated as a falsy value.
The or solution is good for this case. For cases where or is not sufficient, another option is to use the with-exception-default macro from the Tupelo library:
(with-exception-default default-val & body)
"Evaluates body & returns its result. In the event of an exception the
specified default value is returned instead of the exception."
(with-exception-default 0
(Long/parseLong "12xy3"))
;=> 0
Use fnil:
A function that replaces a nil second argument to > with 0 is ...
(fnil > nil 0)
So that, for instance,
((fnil > nil 0) 1 (first []))
=> true
imho you should clearly define the functional objects in your design
since you need a functionality: given a collection coll extract the first element or default to 0 then you should have a separate function for that.
e.g.
(defn first-or-zero [coll]
(if (seq coll)
(first coll) 0))
Although a bit cumbersome to write (and the or macro does seem to get you there quicker you are missing out on the powerful concept that is FP.
a) doing this way you have a pure functional description of what you need to do
b) you can test it either by proof or by unit-testing
c) you can reuse it all over the place with minimum impact on change
A more FP way of doing it would be:
(defn first-or-default
([coll] (first-or-default coll 0))
([coll dflt-val]
(if (seq coll)
(first coll) dflt-val)))
Then just call: (< 1 (first-or-default coll 0))
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 nots 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?
The short answer is to use seq? instead of list?
Here is how I would implement it:
(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)))))))
For forms and expressions, there is no significant difference between a list or a sequence. Alternatively if you did want to preserve listiness, you just need to be a bit more thorough in converting sequences to lists :)
For what it's worth, ...
First, let's define what a logical inverse becomes:
(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)))
Let's test it:
(map inverse ['p '(not p) '(and a b) '(and (not a) b)])
;((not p) p (or (not a) (not b)) (or a (not b)))
It short-circuits double negatives as well as doing the DeMorgan thing.
Now we can express the transformation:
(defn transform [expr]
(if (seq? expr)
(let [[op & args] expr]
(if (= op 'not)
(inverse (first args))
(cons op (map transform args))))
expr))
For example,
(transform '(not (and p q r)))
;(or (not p) (not q) (not r))
Where it finds a not, it returns the inverse of the argument.
Otherwise, it reconstructs the expression, transforming
sub-expressions where it can, just as inverse does.
If we're not fussed about transforming sub-expressions, we can simplify to
(defn transform [expr]
(or (and (seq? expr)
(let [[op & args] expr]
(if (= op 'not) (inverse (first args)))))
expr))
I find pulling out the inverse manipulation easier to follow.
In the simple transform, I've played with and and or and
one-armed if to avoid repeating the do-nothing case that weighs
down OP's text.
How does this relate to #TimothyPratley's answer?
I shamelessly stole his observation on using seq? instead of
list?.
His throws an exception on unrecognised operations. Mine just makes
them nil.
I've factored the ands and ors into a single case.
Calling reverse on the output of the following
(def seq-counter (atom 0))
(defn tokenize-data [data]
(reduce
(fn [out-data-map token]
(if (seq? token)
(conj out-data-map {(keyword (str "DIRECTIVE_" (reset! seq-counter (inc #seq-counter))))token})
(if-not (= token (first '(EQU)))
(conj out-data-map {(keyword (str "DATA_1")) token})
(conj out-data-map {:START '(EQU)}))))
{}
data))
called with
'(EQU (COLOR TABLE) ?)
produces
([:START (EQU)] [:DIRECTIVE_13 (COLOR TABLE)] [:DATA_1 ?])
My question is: What is the ? as a value and how do I compare it (other than what is below)?
I can't seem to test to see if ? is there using \?.
All I can do is compare it like this, and I get the result I want.
(= (last (nth (reverse (tokenize-data '(EQU (COLOR TABLE) ?))) 2)) (first '(?)))
You can prevent Clojure from evaluating any expression by just putting a quote ' in front of that expression. So '(?) quotes a list with ? as its first element without Clojure trying to call the ? function, and (first '(?)) accesses the ? in that list.
To get at the ? symbol directly, simply do '?, which will let you access the symbol itself without Clojure trying to return the value (if any) that is assigned to ?
user=> (= '? (first '(?)))
true
I want to create multiple defs in a file at compile time without having to type everything out. I'd like to do something like:
(ns itervals)
(loop [i 0]
(if (<= i 128)
(do
(def (symbol (str "i" i)) i)
(recur (+ i 1)))))
In that way, we define the variables i1,..., i128 in the current context. I can't figure out a way to do it at compile time without defining them all explicitly. I think macros might be the way to go, but I have no idea how.
This feels more like compile time:
(defmacro multidef[n]
`(do ~#(for [i (range n)]
`(def ~(symbol (str "i" i)) ~i))))
(multidef 128)
i0 ; 0
i127 ; 127
i128 ; unable to resolve
But I can't think of a test that will tell the difference, so maybe the distinction is false.
Try this:
(for [i (range 1 129)]
(eval `(def ~(symbol (str "i" i)) ~i)))