Convert string to parenthesized S-expression in Racket - functional-programming

How can I convert a string like "(+ ( - 5 2) 8)" to an s-expression (+ (- 5 2) 8) that can be evaluated in the Racket prompt? I tried string->symbol but it returns '|(+ ( - 5 2) 8)| which is not what I want.

The read function in racket (or any other lisp) does just this. Except read will read from an input port rather than a string. You can use open-input-string function for that.
(read (open-input-string "(+ (- 5 2))"))

Related

Get value of symbol without evaluating it

It is possible to get value of the symbol unevaluated like this:
(let ((form '(+ 1 2))) `',form)
This expression evaluates to the following:
'(+ 1 2)
Is there some way to do the same thing but without using backquote?
(let ((form '(+ 1 2))) (list 'quote form))
If form is really a constant:
(list 'quote (list '+ '1 '2))
The quotes on 1 and 2 are redundant, since they're literals, but they are informative and are already there in case you replace then with actual expressions.
You can use the longer syntax if you want. Let's see how your form is read and evaluated, step-by-step.
(let ((form '(+ 1 2))) `',form)
Apostrophe is quote:
(let ((form '(+ 1 2))) `(quote ,form))
Backquote/comma (quasiquote) is a shorthand for building data:
(let ((form '(+ 1 2))) (list 'quote form))
Evaluate the let binding, which associates form with its value, literally the list (+ 1 2), inside the lexical environment of this expression:
(list 'quote form)
Te above builds a list made of the quote symbol and the current value bound to form. The above results in a list starting with quote and a sublist, which prints as follows:
(quote (+ 1 2))
... which admits this simpler representation:
'(+ 1 2)
So you can use (list 'quote form) if you prefer, but this is not much different.
(let ((form '(+ 1 2))) `',form)
You ask:
It is possible to get value of the symbol unevaluated...
Actually this not really what it does. By default Common Lisp has local variables using lexical bindings, not symbols having values. Above form computes the value of the variable form, not of the symbol form. The value of form is the list (+ 1 2). With the backquoted quote, you put a list (quote ...) around it. Which gets printed as (QUOTE (+ 1 2)) or '(+ 1 2).
Note that Common Lisp has no way to get from a symbol to the value of a lexical binding. In the source code symbols denote variables, but at runtime we have lexical bindings and not associations from symbols to values.

Average using &rest in lisp

So i was asked to do a function i LISP that calculates the average of any given numbers. The way i was asked to do this was by using the &rest parameter. so i came up with this :
(defun average (a &rest b)
(cond ((null a) nil)
((null b) a)
(t (+ (car b) (average a (cdr b))))))
Now i know this is incorrect because the (cdr b) returns a list with a list inside so when i do (car b) it never returns an atom and so it never adds (+)
And that is my first question:
How can i call the CDR of a &rest parameter and get only one list instead of a list inside a list ?
Now there is other thing :
When i run this function and give values to the &rest, say (average 1 2 3 4 5) it gives me stackoverflow error. I traced the funcion and i saw that it was stuck in a loop, always calling the function with the (cdr b) witch is null and so it loops there.
My question is:
If i have a stopping condition: ( (null b) a) , shouldnt the program stop when b is null and add "a" to the + operation ? why does it start an infinite loop ?
EDIT: I know the function only does the + operation, i know i have to divide by the length of the b list + 1, but since i got this error i'd like to solve it first.
(defun average (a &rest b)
; ...
)
When you call this with (average 1 2 3 4) then inside the function the symbol a will be bound to 1 and the symbol b to the proper list (2 3 4).
So, inside average, (car b) will give you the first of the rest parameters, and (cdr b) will give you the rest of the rest parameters.
But when you then recursively call (average a (cdr b)), then you call it with only two arguments, no matter how many parameters where given to the function in the first place. In our example, it's the same as (average 1 '(3 4)).
More importantly, the second argument is now a list. Thus, in the second call to average, the symbols will be bound as follows:
a = 1
b = ((3 4))
b is a list with only a single element: Another list. This is why you'll get an error when passing (car b) as argument to +.
Now there is other thing : When i run this function and give values to the &rest, say (average 1 2 3 4 5) it gives me stackoverflow error. I traced the funcion and i saw that it was stuck in a loop, always calling the function with the (cdr b) witch is null and so it loops there. My question is:
If i have a stopping condition: ( (null b) a) , shouldnt the program stop when b is null and add "a" to the + operation ? why does it start an infinite loop ?
(null b) will only be truthy when b is the empty list. But when you call (average a '()), then b will be bound to (()), that is a list containing the empty list.
Solving the issue that you only pass exactly two arguments on the following calls can be done with apply: It takes the function as well as a list of parameters to call it with: (appply #'average (cons a (cdr b)))
Now tackling your original goal of writing an average function: Computing the average consists of two tasks:
Compute the sum of all elements.
Divide that with the number of all elements.
You could write your own function to recursively add all elements to solve the first part (do it!), but there's already such a function:
(+ 1 2) ; Sum of two elements
(+ 1 2 3) ; Sum of three elements
(apply #'+ '(1 2 3)) ; same as above
(apply #'+ some-list) ; Summing up all elements from some-list
Thus your average is simply
(defun average (&rest parameters)
(if parameters ; don't divide by 0 on empty list
(/ (apply #'+ parameters) (length parameters))
0))
As a final note: You shouldn't use car and cdr when working with lists. Better use the more descriptive names first and rest.
If performance is critical to you, it's probably best to fold the parameters (using reduce which might be optimized):
(defun average (&rest parameters)
(if parameters
(let ((accum
(reduce #'(lambda (state value)
(list (+ (first state) value) ;; using setf is probably even better, performance wise.
(1+ (second state))))
parameters
:initial-value (list 0 0))))
(/ (first accum) (second accum)))
0))
(Live demo)
#' is a reader macro, specifically one of the standard dispatching macro characters, and as such an abbreviation for (function ...)
Just define average*, which calls the usual average function.
(defun average* (&rest numbers)
(average numbers))
I think that Rainer Joswig's answer is pretty good advice: it's easier to first define a version that takes a simple list argument, and then define the &rest version in terms of it. This is a nice opportunity to mention spreadable arglists, though. They're a nice technique that can make your library code more convenient to use.
In most common form, the Common Lisp function apply takes a function designator and a list of arguments. You can do, for instance,
(apply 'cons '(1 2))
;;=> (1 . 2)
If you check the docs, though, apply actually accepts a spreadable arglist designator as an &rest argument. That's a list whose last element must be a list, and that represents a list of all the elements of the list except the last followed by all the elements in that final list. E.g.,
(apply 'cons 1 '(2))
;;=> (1 . 2)
because the spreadable arglist is (1 (2)), so the actual arguments (1 2). It's easy to write a utility to unspread a spreadable arglist designator:
(defun unspread-arglist (spread-arglist)
(reduce 'cons spread-arglist :from-end t))
(unspread-arglist '(1 2 3 (4 5 6)))
;;=> (1 2 3 4 5 6)
(unspread-arglist '((1 2 3)))
;;=> (1 2 3)
Now you can write an average* function that takes one of those (which, among other things, gets you the behavior, just like with apply, that you can pass a plain list):
(defun %average (args)
"Returns the average of a list of numbers."
(do ((sum 0 (+ sum (pop args)))
(length 0 (1+ length)))
((endp args) (/ sum length))))
(defun average* (&rest spreadable-arglist)
(%average (unspread-arglist spreadable-arglist)))
(float (average* 1 2 '(5 5)))
;;=> 3.25
(float (average* '(1 2 5)))
;;=> 2.66..
Now you can write average as a function that takes a &rest argument and just passes it to average*:
(defun average (&rest args)
(average* args))
(float (average 1 2 5 5))
;;=> 3.5
(float (average 1 2 5))
;;=> 2.66..

Repeat string/character with (format)

Is there a repeat directive for (format) in Common lisp, something like(I know this won't work):
(format t "~5C" #\*)
Just wondering if there isn't a more elegant way to do it than this:(from rosettacode
)
(defun repeat-string (n string)
(with-output-to-string (stream)
(loop repeat n do (write-string string stream))))
(princ (repeat-string 5 "hi"))
(defun write-repeated-string (n string stream)
(loop repeat n do (write-string string stream)))
(write-repeated-string 5 "hi" *standard-output*))
Generally you can use the format iteration:
(format t "~v#{~A~:*~}" 5 "hi")
~A can output all kinds of items, not just characters. For more information see uselpa's linked answers.
Above takes the iteration number from the first argument. Thus the v behind the tilde.
The rest of the arguments will be consumed by the iteration. Thus the #.
Inside the iteration we go back one element. Thus ~:*.
It's similar to (format t "~v{~A~:*~}" 5 '("hi")), which might be simpler to understand.

When would I use mapc instead of mapcar?

So far I have been using mapcar to apply a function to all elements of a list, such as:
(mapcar (lambda (x) (* x x))
'(1 2 3 4 5))
;; => '(1 4 9 16 25)
Now I learned that there is also the mapc function which does exactly the same, but does not return a new list, but the original one:
(mapc (lambda (x) (* x x))
'(1 2 3 4 5))
;; => '(1 2 3 4 5)
What's the intent of this function? When would I use mapc instead of mapcar if I am not able to access the result?
The Common Lisp Hyperspec says:
mapc is like mapcar except that the results of applying function are not accumulated. The list argument is returned.
So it is used when mapping is done for possible side-effects. mapcar could be used, but mapc reduces unnecessary consing. Also its return value is the original list, which could be used as input to another function.
Example:
(mapc #'delete-file (mapc #'compile-file '("foo.lisp" "bar.lisp")))
Above would first compile the source files and then delete the source files. Thus the compiled files would remain.
(mapc #'delete-file (mapcar #'compile-file '("foo.lisp" "bar.lisp")))
Above would first compile the source files and then delete the compiled files.
You should use mapc when you don't need to use the result of applying the function over the list. For example, to print out every element, you could use:
(mapc #'print '(1 2 3 4 5))
Technically, the print function will return something, but you don't need to use it, so you ignore it.

Basic Lisp Macro error

Little help here please . I am trying to create this lisp macro which takes a list (of numbers) as input and returns the sum of those numbers. The code
(setf g (list 1 2 3 4))
(defmacro add-test(var)
`(+ ,#var))
(add-test g) gives this error
The value G is not of type LIST.
[Condition of type TYPE-ERROR]
At the same time (add-test (1 2 3 4)) gives the correct result which is 10.
Can you please explain , why is it not working when variable is passed in to the function?
Other details -
Lispbox - SBCL
Ubuntu Linux
Thanks in advance
That's easy and one of the most common macro questions.
(add-test g)
Now on macro expansion, the macro ADD-TEST is called with the parameter VAR getting the value G, a symbol.
Then you try a list operation. The backquote expression
`(+ ,#var)
The value of VAR is G, and you try to splice that into the list (+ ... ). Now the returned expression is (+ . G).
CL-USER 12 > (macroexpand '(add-test g))
(+ . G)
T
(+ . G) is not a valid Lisp form. It's not valid source code.
Remember, the parameters to a Macro are the unevaluated source expressions.
Compare that with the following:
CL-USER 13 > (macroexpand '(add-test (1 2 3 4)))
(+ 1 2 3 4)
T
You said: 'Can you please explain, why is it not working when variable is passed in to the function?'
Remember, ADD-TEST is NOT a function, it is a macro. A macro gets the source code passed and returns a new form - that form is then later evaluated.

Resources