well I came across a function that I wrote that uses the same code a few times.
here is an example:
(define (get-min&max-from-mixed-list mixedList)
(if (null? (sublist-numbers mixedList))
'()
(min&maxRec (sublist-numbers mixedList)
(first (sublist-numbers mixedList)) ; this
(first (sublist-numbers mixedList))) ; and this
)
)
In a procedural programing language I wouldve done:
int x = (first (sublist-numbers mixedList))
min&maxRec(sublist-numbers(mixedList) , x , x)
From my understanding of Functional languages we don't save stuff in the memory and afterwards, we use them. So how can I not duplicate code?
You can use let to bind a value to a symbol & use that symbol as often as you like within the let body.
The documentation for it & related forms are here: https://docs.racket-lang.org/reference/let.html
You could use it in your example like this:
(define (get-min&max-from-mixed-list mixedList)
(let ((snm (sublist-numbers mixedList)))
(if (null? snm)
'()
(min&maxRec snm
(first snm)
(first snm))
)
)
)
Related
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...
I'm trying to look up atoms of a list passed to the translate function translate the atom to the appropriate number, and output a new list. I'm getting the following error:
outlist: unbound identifier in module in: outlist
Here is my code:
#lang racket
(define chinese '(ling yi er san si wu liu qi ba jiu shi))
(define english '(zero one two three four five six seven eight nine ten))
(define (translate alist)
(cond
((eq? "zero" (car alist) cons ('(0)) outlist)
)
(translate (cdr alist))))
(define list '(zero))
(translate list)
What I'm looking for is to pass translate a list that contains "one two three" etc and get a list from translate with "1 2 3" contained in it..
I've also tried adding
(define outlist '())
inside the translate function and the following error is thrown:
application: not a procedure;
expected a procedure that can be applied to arguments
given: '(0)
arguments...: [none]
Any help is greatly appreciated! Really what I should be doing is looking up the string of the user generated list in english and chinese, then doing the translation, so if you can elaborate on how to do this, that would help as well.
There isn't a parameter or variable called outlist, you're supposed to build the output list as you go - and remember to write a correct base case for the recursion.
Also, there are multiple syntax errors with your code, make sure that you understand how to call a function in Scheme. You should try something like this:
(define (translate alist)
(cond
((null? alist) '())
((eq? 'zero (car alist))
(cons 0 (translate (cdr alist))))
((eq? 'one (car alist))
(cons 1 (translate (cdr alist))))
... and so on ...))
It works as expected:
(translate '(zero one))
=> '(0 1)
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)))
I have a few functions.
(define adjs '(black brown fast hairy hot quick red slow))
(define adj?
(lambda (a) (if (member a adjs) #t #f)
)
(define OK
(lambda (x)
(cond
((equal? x()) #t)
((equal? adj? (car x)) OK(cdr x))
((else x #f))
)
)
)
The function adj? is checking to see if the input is part of the list of adjectives in adjs.
What I am trying to do with the OK function is the user will input a list and have that list run through adj? to see if it is part of the adjs list.
What happens when I run the function is I get an error return that says I entered in "X" amount of arguments when the function only expected two. Why?
There are problems with the parentheses. Some are unnecessary and others are missing, for example when you recursively call the OK procedure, or in the way you're calling adj? - remember, in Scheme we call a procedure like this: (f x), not like this: f(x). Also, the base case of the recursion seems off, and the else clause is used incorrectly. Try this:
(define adj?
(lambda (a)
(if (member a adjs) #t #f)))
(define OK
(lambda (x)
(cond
((null? x) #t)
((adj? (car x)) (OK (cdr x)))
(else #f))))
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)