How to append special characters to a list in Scheme? - functional-programming

I am trying to append ( to an element of a list followed by )
How should it be? I am trying the following:
(append (list 'lambda) (list 'x)) : this compiles and gives the result '(lambda x)
I want the result to be:
(lambda (x))
Any hint?

The simplest way to write it is:
(list 'lambda (list 'x))
If you really must use the append approach mentioned in your question, then one possible solution is:
(append (list 'lambda) (list (list 'x)))

Related

Racket macro that recursively processes a list argument

I'm trying to write a macro that recursively 'unwraps' the values of a list into individual values. For example, unwrap '(1 2 3)) would produce (separately):
(car '(1 2 3)) ; 1
(car (cdr '(1 2 3)) ; 2
(car (cdr (cdr '(1 2 3)) ; 3
This would be used like (+ (unwrap '(1 2 3))) ==> (+ 1 2 3). (I know you can use the standard libary apply for this, but I'm trying to write my own version).
My problem is that in writing the macro, I don't know how to recursively process the list argument passed into the unwrap macro. Here's what I've tried:
(define-syntax (unwrap stx)
(syntax-case stx ()
[(_ lst)
#`(begin (car lst) ; error at the last step since (car '()) is invalid
(unwrap (cdr lst)))]))
or
(define-syntax (unwrap stx)
(syntax-case stx ()
[(_ lst)
#`(if (null? lst)
'()
(car (unwrap (cdr lst))))])) ; infinite loops
These are both obviously wrong, but essentially I don't know write a macro that check the value of the input list (or matches against an empty list pattern) and returns something different in either scenario. It's also possible I'm approaching this entirely wrong, so any help would be greatly appreciated. Thank you!
You want
(+ (unwrap '(1 2 3))) ==> (+ 1 2 3)
but this is impossible. You are asking for unwrap to macroexpand to three disconnected forms, which is not allowed. Any macro must expand into exactly one form. So as you say in your question, for the example you gave, apply is the right answer.
For other possible usages, the answer is to back up a step and ask why you think this unwrap function would be useful: what cases do you hope to use it in? Then design a different solution, that works within the constraints of the language.

how can I write the lisp function to use the predicate

for example, what should I input is here finfirst #'oddp '(1 2 3), and it should find the first odd number return to the list, so what I think I need to do is to write a function just have one argument which is list, but I only know to find the first element in the list, so how can I use the condition in my code
(defun finfirst(list)(cond((null list) nil)
if I finish this, then it will told me that I need two argument, I just don't know what should I do for this function, just give me some hint for that
If you just want the functionality you described, you can use the function find-if, eg:
(find-if #'oddp '(1 2 3))
If you want to implement it yourself, you could do something like this:
(defun finfirst (function list)
(cond
((null list) nil)
((funcall function (first list)) (first list))
(t (finfirst function (rest list)))))
Then use it like this:
(finfirst #'oddp '(1 2 3))

LISP Cannot take CAR of T

I am trying to evaluate each atom of a list and see if it's equal to the number provided and remove if its not but I am running into a slight problem.
I wrote the following code:
(defun equal1(V L)
(cond((= (length L) 0))
(T (cond( (not(= V (car(equal1 V (cdr L))))) (cdr L) )))
)
)
(equal1 5 '(1 2 3 4 5))
I obtain the following error
Error: Cannot take CAR of T.
If I add (write "hello") for the action if true, the following error is obtained:
Error: Cannot take CAR of "hello".
I'm still quite new to LISP and was wondering what exactly is going on and how could I fix this so I could evaluate each atom properly and remove it if its not, thus the cdr L for the action.
car and cdr are accessors of objects of type cons. Since t and "hello" are not cons you get an error message.
To fix it you need to know what types your function returns and not car unless you know that it's a cons
EDIT
First off ident and clean up the code.. The nested cond are uneccesary since cond is a if-elseif-else structure by default:
(defun remove-number (number list)
(cond ((= (length list) 0)
t)
((not (= number (car (remove-number number (cdr list)))))
(cdr list))))
(t
nil)))
I want you to notice I've added the default behaviour of returning t when a consequent is not given as we know = returns either t or nil so it returns t when the length is 0 in this case.
I've added the default case where none of the two previous predicates were truthy and it defaults to returning nil.
I've named it according to the functions used. = can only be used for numeric arguments and thus this will never work on symbols, strings, etc. You need to use equal if you were after values that look the same.
Looking at this now we can see that the functions return value is not very easy to reason about. We know that t, nil and list or any part of the tail of list are possible and thus doing car might not work or in the case of (car nil) it may not produce a number.
A better approach to doing this would be:
check if the list is empty, then return nil
check if the first element has the same numeric value as number, then recurse with rest of the list (skipping the element)
default case should make cons a list with the first element and the result fo the recursion with the rest of the list.
The code would look something like this:
(defun remove-number (number list)
(cond ((endp list) '())
((= (car list) number) (remove-number ...))
(t (cons ...))))
There are a couple of things you could do to improve this function.
Firstly, let's indent it properly
(defun equal1 (V L)
(cond
((= (length L) 0))
(T (cond
((not (= V (car (equal1 V (cdr L))))) (cdr L))))))
Rather than saying (= (length l) 0), you can use (zerop (length l)). A minor sylistic point. Worse is that branch returns no value. If the list L is empty what should we return?
The issue with the function is in the T branch of the first cond.
What we want to do is
remove any list item that is the same value as V
keep any item that is not = to V
The function should return a list.
The expression
(cond
((not (= V (car (equal1 V (cdr L))))) (cdr L)))
is trying (I think) to deal with both conditions 1 and 2. However it's clearly not working.
We have to recall that items are in a list and the result of the equal function needs to be a list. In the expression above the result of the function will be a boolean and hence the result of the function call will be boolean.
The function needs to step along each element of the list and when it sees a matching value, skip it, otherwise use the cons function to build the filtered output list.
Here is a skeleton to help you out. Notice we don't need the embedded cond and just have 3 conditions to deal with - list empty, filter a value out, or continue to build the list.
(defun equal-2 (v l)
(cond
((zerop (length L)) nil)
((= v (car l)) <something goes here>) ;skip or filter the value
(t (cons (car l) <something goes here>)))) ;build the output list
Of course, this being Common Lisp, there is a built-in function that does this. You can look into remove-if...

create a list with the given number of strings

I am trying to create a list with a given number of strings. So, if I enter (make-row 3) it will be '("ivy" "ivy" "ivy") and if I enter (make-row 2) it will be '("ivy" "ivy).
I currently have the following code but it doesn't work:
(define (make-row a)
(cond
((= 0 a) '())
(else
(list "ivory")
(make-row (- a 1)))))
Can you please tell me how to write this code or what I doing wrong? I am learning how to program with Typed/Racket at home so don't have access to teachers or mentors :(
Just use one of the built-in procedures:
(define (make-row a)
(make-list a "ivory"))
But if you want to do it from scratch, use the standard template for building an output list by consing the results. Notice that your code won't work because of that (list "ivory") in the middle of nowhere - only the last expression of a condition is returned, and anyway that's not how we recursively build a list. Try this:
(define (make-row a)
(cond ((= 0 a) '())
(else (cons "ivory" (make-row (- a 1))))))
Either way, it works as expected:
(make-row 3)
=> '("ivory" "ivory" "ivory")

Adding numbers from a list (e.g. asdf125dkf will return 8)

I need a function that will take in a list of characters and numbers, and then return the numbers added up (ignoring the characters). This is what I have so far:
(define (adder lst)
(cond
((null? lst)
0)
((number? (car lst))
(+(adder (car lst)) (adder (cdr lst))))
((char? (car lst))
((adder(cdr lst))))
))
(display (adder '(asd12sdf)))
Running it on codepad.org just displays void. I know the code is wrong because it looks wrong, but I have no idea how to fix it... How do I have the function keep track of the first number it finds and add it to the next one it finds, while skipping all characters?
In your second cond case, there's no reason to run adder on (car lst). Just adding (car list) itself to the recursive step should work.
For the last line, don't test (char? (car lst)). Just make the last line the else clause, meaning that anything BUT a number will go to the else line.
The reason you're getting void is because your input doesn't satisfy any of the cond conditions, and you have no else, so the answer is nothing (i.e. (void)).
The last mistake is in the input you're giving it. '(asd12sdf) is literally a list with one symbol named "asd12sdf". I think you want to give it '(a s d 1 2 s d f) (a list of 6 symbols and 2 numbers) which should result in 3. Notice that there's a very important difference between the symbol 'a and the character #\a.
It looks like you have the logic down, so your problem doesn't seem to be functional languages, just Scheme's syntax.
Edit: and in the last line, you have ((adder(cdr lst))) which has one too many parens wrapped around it. That will cause Scheme to attempt to evaluate the result of adder (which is a number) as a procedure (error!).
You should observe that this function is more or less sum which can be defined simply by using fold.
(define (adder lst)
(fold + 0 lst))
What does fold do? Basically, it's defined like so:
(define (fold f initial lst)
(if (null? lst)
initial
(fold f (f (car lst) initial) (cdr lst))))
(In other words, it calls f, a function of 2 arguments, on each element of lst, using the car of the lst as the first argument, and the accumulated result as the second argument to f.)
The issue here which you need to address is that + doesn't know how to operate on non-numeric values. No problem, you've already dealt with that. What happens if it's a character instead? Well, you're not adding anything to the total value, so replace it with a 0. Therefore, your solution is as simple as:
(define (adder lst)
(fold your-new-protected-+ 0 lst))
In Common Lisp:
(reduce #'+ '(1 #\a #\b 2 1 2 #\c #\d 4)
:key (lambda (item) (if (numberp item) item 0)))
or
(loop for item in '(1 #\a #\b 2 1 2 #\c #\d 4)
when (numberp item) sum item)

Resources