How to Extract Clojure string to enumerable of strings? - functional-programming

Suppose I have a simple string that I want to parse into array of string:
"add (multiply (add 1 2) (add 3 4)) (add 5 6)"
How do I parse it into 3 strings (based on outer parentheses):
add
(multiply (add 1 2) (add 3 4))
(add 5 6)
With my OOP mind, I think I need a for loop index and if else statement to do this.
I have tried parse it with string split, however I got:
command
(multiply
1
(add
3
2))
(add
3
4)
which is not what I expected

since your data elements are already in the well formed polish notation, you can simply read it as edn, and operate on the clojure's data structures:
(def s "add (multiply (add 1 2) (add 3 4)) (add 5 6)")
(map str (clojure.edn/read-string (str "(" s ")")))
;;=> ("add" "(multiply (add 1 2) (add 3 4))" "(add 5 6)")
i'm still unaware of your end goal, but this seems to fulfill the asked one.

Either you can use the build-in LispReader
(import '[clojure.lang LispReader LineNumberingPushbackReader])
(import '[java.io PushbackReader StringReader])
(defn could-read? [pr]
(try
(LispReader/read pr nil)
true
(catch RuntimeException e false)))
(defn paren-split2 [s]
(let [sr (StringReader. s)
pr (LineNumberingPushbackReader. sr)
inds (loop [result [0]]
(if (could-read? pr)
(recur (conj result (.getColumnNumber pr)))
result))
len (count s)
bounds (partition 2 1 inds)]
(for [[l u] bounds
:let [result (clojure.string/trim (subs s l (min len u)))] :when (seq result)]
result)))
(paren-split2 "add ( multiply ( add 1 2) (add 3 4)) (add 5 6 )")
;; => ("add" "( multiply ( add 1 2) (add 3 4))" "(add 5 6 )")
or you can hand-code a parser:
(def conj-non-empty ((remove empty?) conj))
(defn acc-paren-split [{:keys [dst depth current] :as state} c]
(case c
\( (-> state
(update :depth inc)
(update :current str c))
\) (if (= 1 depth)
{:depth 0 :dst (conj-non-empty dst (str current c)) :current ""}
(-> state
(update :depth dec)
(update :current str c)))
\space (if (zero? depth)
{:depth 0 :dst (conj-non-empty dst current) :current ""}
(update state :current str c))
(update state :current str c)))
(defn paren-split [s]
(:dst (reduce acc-paren-split
{:dst []
:depth 0
:current ""}
s)))
(paren-split "add ( multiply ( add 1 2) (add 3 4)) (add 5 6 )")
;; => ["add" "( multiply ( add 1 2) (add 3 4))" "(add 5 6 )"]
Note: Either approach will preserve spaces in the input strings.

You could use read-string from clojure core to use the built-in reader of clojure. Here we read-in, use str to generated of the read-in chunk a string
and subtract it from the string, clojure.string/trim the ends then, to start the cycle anew, until after trimming an empty string occurs.
Then, the collected result is returned.
(defn pre-parse [s]
(loop [s s
acc []]
(if (zero? (count s))
acc
(let* [chunk (read-string s)
s_ (str chunk)
rest-s (clojure.string/trim (subs s (count s_)))]
(recur rest-s (conj acc s_))))))
recure takes its arguments, and calls loop on it with the arguments given in the order as loop takes them.
We can test it with:
(def x "add (multiply (add 1 2) (add 3 4)) (add 5 6)")
(pre-parse x)
;; => ["add" "(multiply (add 1 2) (add 3 4))" "(add 5 6)"]

Related

Delete occurences of item from non-linear list

I am trying to delete all occurrences of an element from a list, from any levels of the list. I am required to use a map function though. I am using Common Lisp. For example I'd want to be able to do:
(fdelete '(1 2 3 4 (3)) 3) => (1 2 4)
What I've tried so far:
This function will do what's needed, sort of. It will replace all occurences of the given element with NIL, so it's not exactly what I want.
(defun fdelete (l e)
(cond
((null l) 0)
((equal l e) nil)
((atom l) l)
(t (mapcar (lambda(l) (fdelete l e )) l ))
)
)
This will do
(fdelete '(1 2 3 4 (3)) 3) => (1 2 NIL 4 (NIL))
My second try is with the mapcap function, since this one won't return a list the same size as the input list.
This will do what's needed, but it will 'destroy' my initial list, as in, it will bring all sublists 'to surface'.
(defun fdelete (l e)
(cond
((null l) 0)
((equal l e) nil)
((atom l) (list l))
(t(mapcan(lambda(x) (fdelete x e ))l ))
)
)
So this indeed does (fdelete '(1 2 3 4 (3)) 3) => (1 2 4)
but it will also do it wrong if I for example try this:
(fdelete '(1 2 3 (4) (3)) 3)) => (1 2 4)
I'd want it to do (fdelete '(1 2 3 (4) (3)) 3)) => (1 2 (4))
I hope my question is well formed and detailed enough, and I am providing working examples. Can someone give me a few hints on how to solve this problem?
Using mapcan is the correct choice since you can wrap in list to get a value or use nil to get item removed. For the list element, if it doesn't already match what to delete, you should check the result of the recursion and wrap it if it's not the empty list.
The solution would look something like:
(defun remove-deep (item list)
(mapcan (lambda (cur)
(cond ((equal item cur) '())
...))
list))
(remove-deep 3 '(1 nil 2 3 (3) (3 4)))
; ==> (1 nil 2 (4))
To apply the principle of least surprise I have renamed the function since delete is the destructive version of remove. Also I kept the argument order of the standard functions:

clojure recursion conj a list

((fn foo [x] (when (> x 0) (conj (foo (dec x)) x))) 5)
For this code, the result is [5 4 3 2 1]
Why isn't is [1,2,3,4,5]?
I see we do conf from result of recursive foo call with a value.
For I thought it should be 1 2 3 4 5?
Need help to understand this.
Thanks.
From the documentation of conj:
clojure.core/conj
([coll x] [coll x & xs])
conj[oin]. Returns a new collection with the xs
'added'. (conj nil item) returns (item). The 'addition' may
happen at different 'places' depending on the concrete type.
The termination condition of your function yields nil, because the test is a when. So the deepest conj call will be:
(conj nil 1)
(1) <-- a list
The next one:
(conj (conj nil 1) 2)
(2 1)
So your result will be in decreasing order because conj appends at the front for lists. If you want it in increasing order, start with an empty vector like this:
((fn foo [x] (if (> x 0) (conj (foo (dec x)) x) [])) 5)
[1 2 3 4 5]
The recursive call expands to
(conj (conj (conj (conj (conj nil 1) 2) 3) 4) 5)
;(5 4 3 2 1)
The implicit nil returned by (foo 0) puns to ().

Why I'm getting a list instead of a vector?

So, I'm trying to transform each element of a vector x,in this way: x[i]--> 1-(1/x[i])
(defn change[x]
(fn [i]
(assoc x i (- 1 (/ 1 (get x i))))
)
(range 0 (* (count x) 1))
)
I'm using assoc to replace each element of the vector, I'm supposed to get a vector with the changes, but instead I'm getting a list.
For example
user> (change [21 32 23 34])
(0 1 2 3)
But I should get a vector :v
The code for the function you provided doesn't use the local anonymous function, and can be refactored greatly.
This is your original function with comments.
(defn change[x]
;; start unused anonymous
(fn [i]
(assoc x i (- 1 (/ 1 (get x i)))))
;; end unused anonymous
;; start/end gen list of ints
(range 0 (* (count x) 1)))
This is probably what you mean
(defn change [coll]
(mapv #(- 1 (/ 1 %)) coll))
And this is the output
user> (change [21 32 23 34])
;=> [20/21 31/32 22/23 33/34]
What your code does
Your original code (reformatted)
(defn change [x]
(fn [i] (assoc x i (- 1 (/ 1 (get x i)))))
(range 0 (* (count x) 1)))
evaluates and discards a function value then
returns the range.
So you can omit the fn form and reduce it to
(defn change [x]
(range 0 (* (count x) 1)))
which in turn reduces to
(defn change [x]
(range (count x)))
So, for example,
(change [:whatever :I :choose :to :put :here])
;(0 1 2 3 4 5)

Pointers in Common Lisp

I want to save a reference (pointer) to a part of some Data I saved in another variable:
(let ((a (list 1 2 3)))
(let ((b (car (cdr a)))) ;here I want to set b to 2, but it is set to a copy of 2
(setf b 4))
a) ;evaluates to (1 2 3) instead of (1 4 2)
I could use macros, but then there would ever be much code to be executed if I want to change some Data in the middle of a list and I am not very flexible:
(defparameter *list* (create-some-list-of-arrays))
(macrolet ((a () '(nth 1000 *list*)))
(macrolet ((b () `(aref 100 ,(a))))
;; I would like to change the macro a here if it were possible
;; but then b would mean something different
(setf (b) "Hello")))
Is it possible, to create a variable as a reference and not as a copy?
cl-user> (let ((a '(1 2 3)))
(let ((b (car (cdr a))))
(setf b 4))
a)
;Compiler warnings :
; In an anonymous lambda form: Unused lexical variable B
(1 2 3)
A cons cell is a pair of pointers. car dereferences the first, and cdr dereferences the second. Your list is effectively
a -> [ | ] -> [ | ] -> [ | ] -> NIL
| | |
1 2 3
Up top where you're defining b, (cdr a) gets you that second arrow. Taking the car of that dereferences the first pointer of that second cell and hands you its value. In this case, 2. If you want to change the value of that pointer, you need to setf it rather than its value.
cl-user> (let ((a '(1 2 3)))
(let ((b (cdr a)))
(setf (car b) 4))
a)
(1 4 3)
If all you need is some syntactic sugar, try symbol-macrolet:
(let ((a (list 1 2 3 4)))
(symbol-macrolet ((b (car (cdr a))))
(format t "~&Old: ~S~%" b)
(setf b 'hello)
(format t "~&New: ~S~%" b)))
Note, that this is strictly a compile-time thing. Anywhere (in the scope of the symbol-macrolet), where b is used as variable, it is expanded into (car (cdr a)) at compile time. As Sylwester already stated, there are no "references" in Common Lisp.
I wouldn't recommend this practice for general use, though.
And by the way: never change quoted data. Using (setf (car ...) ...) (and similar) on a constant list literal like '(1 2 3) will have undefined consequences.
Building on what Baggers suggested. Not exactly what you are looking for but you can define setf-expanders to create 'accessors'. So lets say your list contains information about people in the for of (first-name last-name martial-status) and when someone marries you can update it as:
(defun marital-status (person)
(third person))
(defun (setf marital-status) (value person)
(setf (third person) value))
(let ((person (list "John" "Doe" "Single")))
(setf (marital-status person) "Married")
person)
;; => ("John" "Doe" "Married")

stuck in recursion of clojure - missing a bracket

I am writing a clojure recursion function so that given:
(luty [1 2 3 4])
should have output like this:
((1 2 3 4) (2 3 4) (3 4) (4) ()
My code is:
(defn luty [a1]
(if (empty? a1)
(list )
(cons (seq a1) (luty (rest a1) )
)))
I am getting output:
((1 2 3 4) (2 3 4) (3 4) (4)) //comment missing a ()
Can anybody suggest me where I am getting wrong?
If we print out the process and look at the second to last opperation:
user> (defn luty [a1]
(println "a1 is" a1)
(if (empty? a1)
()
(cons (seq a1) (luty (rest a1)))))
#'user/luty
user> (luty [1 2 3 4])
a1 is [1 2 3 4]
a1 is (2 3 4)
a1 is (3 4)
a1 is (4)
a1 is ()
((1 2 3 4) (2 3 4) (3 4) (4))
user> (cons '(4) ())
((4))
We can see that the result of adding (4) to the empty list is ((4)) rather than ((4) ()) as you would most likely want. This can be fixed by making the base case a list containing the empty list, instead of just an empty list
user> (defn luty [a1]
(if (empty? a1)
'(())
(cons (seq a1) (luty (rest a1)))))
#'user/luty
user> (luty [1 2 3 4])
((1 2 3 4) (2 3 4) (3 4) (4) ())
The return value of cons is a list with as the first element the first argument and the rest of the list as the second argument. If the second argument is empty or nil, that means you get a list with the first argument as the single member.
The reason for this is that lists are (conceptually, at least, in clojure) linked lists with 2-space cells; one pointer for the head element and one pointer for the tail (another list, which in clojure is guaranteed to be a seq-like thing - in many other lisps you can set the second pointer to any value you want, so you're not guaranteed to get a "proper" list out of a cons there). A nil in the "tail" position marks the end of the list.
Lists are the most easily implemented and understandable persistent (in the clojure sense of immutable, structure-sharing) data structure.
Just to give you a different way of looking at it:
user> (defn luty [a1]
(reductions (fn [c _] (rest c)) (or (seq a1) '()) (-> a1 count range)))
=> #'user/luty
user> (luty [1 2 3 4])
=> ((1 2 3 4) (2 3 4) (3 4) (4) ())
user> (luty [])
=> (())
user> (luty nil)
=> (())

Resources