I was trying to print out a list of symbols and I was wondering if I
could remove the quotes.
(def process-print-list
(fn [a-list]
(cond (empty? a-list) 'false
(list? a-list) (let [a a-list] (println (first a)) (process-print-
list (rest a) ))
:else (process-print-list (rest a-list) ))))
the list is ('x 'y 'z))
with the following output:
(quote x)
(quote y)
(quote z)
I am Just trying to get it to print out:
x
y
z
('x 'y 'z) is a syntactic abbreviation for ((quote x) (quote y) (quote z)). If you actually want a list of symbols (i.e. (x y z)), you're probably quoting too much somewhere.
'(x y z) ;=> (x y z)
'('x 'y 'z) ;=> ((quote x) (quote y) (quote z))
(list 'x 'y 'z) ;=> (x y z)
Generally, do not construct lists using quotation unless you know what you're doing. Use the list constructor instead.
On another note, I'd choose iteration over recursion here. This works fine:
(doseq [sym some-list]
(println sym))
You should use name fn to get symbol name.
(def my-list (list 'x 'y 'z))
(defn process-list
[a-list]
(map #(name %) a-list))
(process-list my-list)
;=> ("x" "y" "z")
Or with printing
(defn process-print-list
[a-list]
(doall (map #(println (name %)) a-list))
nil)
(process-print-list my-list)
;x
;y
;z
;=>nil
Or combine those to get return type you want...
Related
I am trying to convert logical functions in clojure. I want the user to be able to type in (convert '(and x y z) to produce (nor (nor x) (nor y) (nor z). So I am creating a list with first element nor, and then trying to make the rest of the elements lists that are created when going through a for loop. However the for loop just combines all the lists, and keeps the nor outside of it. I also want to know how to skip the first element in the list but that's not my priority right now. I'm kinda new to clojure and can't figure out how to just return all of the lists to be put into the bigger list. The not and or function aren't related to the problem.
(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"))))
The output I get is (nor ((nor (and x y z)))). The output I want is (nor (nor and) (nor x) (nor y) (nor z). I don't want the (nor and) either but until I can figure out how to skip the first element I just want to be able to separate the lists out.
There are two problems that I can see:
makelist has (for [i [l]] ...) so it only produces a single item where i is bound to the whole of the incoming list l -- what you want here is (for [i l] ...) so that each element of l is processed,
convert's clause for and creates a list with two elements: nor and the result of (makelist l) -- what you want here is (cons 'nor (makelist l)) so that you get a list with nor as the first element and then all of the elements of the result of calling makelist.
I haven't checked the other two parts of convert to see whether you have similar errors, but with the two changes above (convert '(and x y z)) will produce (nor (nor and) (nor x) (nor y) (nor z))
just for fun: i would mentally expand and generalize your task to rewriting data structures according to some rules, so you could declare (possibly recursive) rewrite rules to transform any input to any desired output in general. (and to practice clojure)
let's start with simple conversion function:
(defn convert [rules data]
(if-let [res (some (fn [[condition rewrite]]
(when (condition data) (rewrite data)))
rules)]
res
data))
it finds first rule that suits your input (if any) and applies it's transformation function:
(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"))
with this approach, your rules would look something like this:
(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))
ok it works, but looks rather ugly. Still we can elimnate some repetitions introducing couple of basic functions for checkers and transformers:
(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)))
transforming your rules to:
(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))
and then introducing replacing rewrite rule:
(defn replacing
([new] [(constantly true) (constantly new)])
([old new] [#{old} (constantly new)]))
leading us to
(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)))]])
now we can see that there is a demand on a function, transforming every item in collection. let's introduce it:
(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))
now it is much better, but the last clause is still kind of ugly. I can think of introducing the function that transforms head and tail with separate rules and then conses transformed head and tail:
(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))
I'm new to clojure and tried to implement the some function (for some specific tests):
(my-some even? [1 2 3 4]) => true
(my-some #{3 4} [1 2 3 4]) => 3
(my-some zero? [1 2 3 4]) => nil
That's what I came up with so far:
(defn my-some [f x]
(loop [[y & t] x]
(if (empty? t) nil
(if (f y)
(f y)
(recur t)))))
I could imagine there are more idiomatic approaches.
Any suggestions?
Firstly, you have a bug: [[y & t] x] destructures x, but the following empty? check on t means you are ignoring the last element in the sequence. You can see this with
(my-some even? [2])
=> nil
You can replace (if (empty? x) nil (else-form)) with when and seq:
(when (seq x) ...)
you can then use first and next to deconstruct the sequence:
(defn my-some [f x]
(when (seq x)
(if (f (first x))
(f (first x))
(recur f (rest x)))))
the call to recur is then back into my-some so you need to pass the predicate f.
you can replace (if x x (else ....)) with (or x (else ...)):
(defn my-some [f x]
(when (seq x)
(or (f (first x)) (recur f (next x)))))
you can compare this with the implementation of some
I am attempting to write a recursive lambda function (accepting two arguments) that finds the intersection between two (potentially) unsorted sets. Here is the code, which I believe most will find straight forward:
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out))))
(inner (rest x) y (cons (first x) out))
(inner a b '[])
)
I hope to use this lambda function intersection in place of the underscore _ that follows:
(= (__ #{0 1 2 3} #{2 3 4 5}) #{2 3})
However, this code fails to compile, insisting that Java is Unable to resolve symbol: inner in this context...
Any suggestions?
source: http://www.4clojure.com/problem/81
You could try :
#(set (filter %1 %2))
Since sets are functions (see another useful example there). The syntax with %1 and %2 is the same as writing :
(fn [s1 s2] (set (filter s1 s2)))
Or even more succinctly :
(comp set filter)
Regarding the inner error, you simply misplaced the parens (but I don't really see the logic otherwise) :
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out)))
(inner (rest x) y (cons (first x) out))
(inner a b '[])))
If you insist on building the set manually (which I did not so long ago), you could end up with something like that :
(fn [s1 s2]
(reduce #(if (contains? s2 %2) (conj %1 %2) %1) #{} s1))
But really the first solution is the most elegant.
So I've been solving a 4clojure problem, where I need to implement the function flatten and I am trying to debug my solution, which is:
(defn fn1 [x]
(if (not (or (list? x) (vector? x)))
(list x)
(if (empty? (rest x))
(if (not (or (list? x) (vector? x)))
(list x)
(fn1 (first x))
)
(if (or (list? (first x)) (vector? (first x)))
( concat (fn1 (first x)) (fn1 (rest x)) )
( concat (fn1 (list (first x))) (fn1 (rest x)) )
)
)
)
)
While trying to debug, I encountered the following behaviour:
user=> (fn1 (rest [1[2]]))
(([2]))
user=> (rest [1[2]])
([2])
user=> (fn1 '([2]))
(2)
What is the reason behind that and how can I get around it?
I haven't looked to much in your code, but it looks like because
> (type (rest [1 2]))
clojure.lang.PersistentVector$ChunkedSeq
> (vector? (rest [1 2]))
false
> (list? (rest [1 2]))
false
> (seq? (rest [1 2]))
true
So if rest of list is a list, rest of vector is not a list or vector,
but ChunkedSeq
Although they render the same at the REPL, (rest [1 [2]]) and '([2]) have different types:
(type (rest [1 [2]])) ; clojure.lang.PersistentVector$ChunkedSeq
(type '([2])) ; clojure.lang.PersistentList
The former answers false to list? whereas the latter answers true.
I'm still pretty new to clojure, so I apologize if this a bit trivial. Basically, the issue is in the "then" part of the if statement: (if (symbol? (first slist)).
;counts the number of occurences of
(defn count-occurrences [s slist]
(if (empty? slist)
0
(if (symbol? (first slist))
(if (= (first slist) s)
(+ 1 (count-occurrences s (rest slist)))
(+ 0 (count-occurrences s (rest slist))))
(count-occurrences s (first slist))))) ;Problem on this line
(println (count-occurrences 'x '((f x) y (((x z) x)))))
To count elements in a nested list, you could try this function:
(defn count-occurrences [s slist]
(->> slist
flatten
(filter #{s})
count))
Test:
user> (count-occurrences 'x '((f x) y (((x z) x))))
;; => 3
user> (count-occurrences 'y '((f x) y (((x z) x))))
;; => 1
user> (count-occurrences 'z '((f x) y (((x z) x))))
;; => 1
As Diego Basch commented, the skeleton of your algorithm ought to be
(defn count-occurrences [s slist]
(+ (count-occurrencies s (first slist))
(count-occurrencies s (rest slist))))
... which has one or two little problems:
It never terminates.
It doesn't deal with a symbol.
It doesn't deal with an empty list.
slist might not be a list, and eventually, through first calls,
won't be.
How do we deal with these problems?
First, test whether were dealing with a symbol.
If we aren't, assume it's a list and test whether it's empty.
If not, apply the skeleton recursion.
... giving us something like this:
(defn count-occurrences [s x]
(if (symbol? x)
(if (= x s) 1 0)
(if (empty? x)
0
(+ (count-occurrences s (first x))
(count-occurrences s (rest x))))))
... which works:
(count-occurrences 'x '((f x) y (((x z) x))))
;3
This solution has several problems (which you'll come to appreciate) that make Mark's answer superior in practice. However, if you're trying to get to grips with recursion, this will do nicely.