This question might be so easy, but I spent some time on it and I could not figure out what the problem is. I am new to Scheme ;)
Okay, this is my code:
(define foo
(lambda (x)
((if(equal? (car x) 4) "A" "B")
(if(equal? (car (cdr x)) 3) "A" "B")
(if(equal? (car(cdr (cdr x))) 5) "A" "B")
)
))
(foo '(4 3 5))
I get the following error, when I run the code:
> application: not a procedure; expected a procedure that can be
> applied to arguments given: "A" arguments...: "A" "A"
To fix the error, simply do this:
(define foo
(lambda (x)
(if (equal? (car x) 4) "A" "B")
(if (equal? (car (cdr x)) 3) "A" "B")
(if (equal? (car (cdr (cdr x))) 5) "A" "B")))
The problem? that in your code there's an extra and erroneous pair of () surrounding the if expression, so Scheme thinks that if is returning a function (which is not). Remember, in Scheme this: (f) means: execute f as a function with no arguments.
Now that we found the syntax error, let's see what else is wrong with the code. For starters, if you write a sequence of expressions inside a procedure only the value of the last one is returned, so the first two ifs are being completely ignored! After reading the comments I understand that you want to return "AAA" for the input '(4 3 5), or "ABA" for input '(4 6 5). The trick here is that we must use string-append to stick together all the strings:
(define foo
(lambda (x)
(string-append
(if (equal? (car x) 4) "A" "B")
(if (equal? (cadr x) 3) "A" "B")
(if (equal? (caddr x) 5) "A" "B"))))
Now it works as expected:
(foo '(4 3 5))
=> "AAA"
(foo '(4 6 5))
=> "ABA"
Let me start off by saying, "Welcome to Scheme!" Don't get frustrated and whatever you do, keep on
trying to understand the functional-programming way of doing things.
Your perseverance will pay off, and you will become a better programmer
for the effort, even when you go back to using Java.
Scheme is a good place to start learning functional programming.
I hope the following will help you to see how you might start to
change your thinking, so here goes:
Here is a bit about why you got the weird error you saw. If you
have:
(define foo
(lambda (x)
((if(equal? (car x) 4) "A" "B")
(if(equal? (car (cdr x)) 3) "A" "B")
(if(equal? (car(cdr (cdr x))) 5) "A" "B")
)
))
Then:
(foo '(4 3 5))
is equal to:
((if (equal? (car '(4 3 5)) 4) "A" "B"))
(if (equal? (car (cdr '(4 3 5))) 3) "A" "B")
(if (equal? (car (cdr (cdr '(4 3 5)))) 5) "A" "B"))
Because that is what you get when you replace every occurrence
of x with (4 3 5) in the body of the lambda-expression you wrote.
This next bit of reasoning is a bit of a shortcut, but notice that:
(car '(4 3 5)) = 4
AND
(car (cdr '(4 3 5))) = (car '(3 5)) = 3
AND
(car (cdr (cdr '(4 3 5)))) = (car (cdr '(3 5))) = (car '(5)) = 5
So, when we substitute equals for equals in the above expression,
we get:
((if (equal? 4 4) "A" "B")
(if (equal? 3 3) "A" "B")
(if (equal? 5 5) "A" "B"))
and this is the same as:
("A" "A" "A")
This is a peculiar Scheme expression, and the reason Scheme complains is
because you're trying to invoke a function called "A" and apply it to
two arguments, "A" and "A".
From the discussion above, it's pretty clear that you're trying to
derive a new structure, based on the input. So, what you need is
a function which derives the new structure, based on an examination
of the existing structure, and assembles a new one. This is what
is returned by the function.
Scheme is a functional language, which means that it is very
expression-oriented. In Scheme, the computer is turned into a kind of
mechanical expression-evaluator. This is very different from
what we became used to in object-oriented languages (e.g., Java,
C#) because those languages are all about carefully controlling
changeable state. In functional languages, it's all about
calculating the value of an expression. (By the way, In a deep
and beautiful way, it just so happens that everything you can
do in the world of "mutable state programming" can be done in
the world of "mechanical evaluation of expressions." There's a
deep and fundamental equivalence between the two, believe it or not.)
If you are trying to create a new list, based on tests of the individual
elements in list (4 3 5), then you need to write expressions which do
two separate things: construct lists from smaller things, and examine
the various elements of the list (in this case, 4, 3, and 5.)
(define foo
(lambda (x)
(cons (if (equal? (car x) 4) "A" "B")
(cons (if (equal? (car (cdr x)) 3) "A" "B")
(cons (if (equal? (car (cdr (cdr x))) 5) "A" "B") '() )))))
So, (foo '(4 3 5)) results in ("A" "A" "A"), which is a list of strings.
You eventually want to append them all together into a single string,
right? So, there's already a function called fold-right which provides
a way to do this. The fold-right function can use the string-append
function to accomplish this:
(fold-right string-append "" (foo '(4 3 5)))
which should provide an answer of "AAA".
(fold-right string-append "" (foo '(4 4 4)))
gives an answer of "ABB"
Using functions like fold, fold-right, etc, is a more of a functional
programming way to do these kinds of things.
Depending on the circumstances, you may want to use those folding functions
instead of writing the foo function in terms of the string-append function, as
Oscar Lopez did above.
Like I said earlier, you have to think about things very differently
when using a functional programming language, and get away from thinking
of programs as sequences of operations which change the internal state
of the computer's memory. You have to start thinking in terms of the
computer as a powerful expression evaluation machine instead.
I hope this helps, and is an encouragement to you to keep working at learning Scheme.
Because the body of your lambda is wrapped in parentheses, the first if is being treated as a procedure, and when it tries to apply the results of the other if's to it, you get the error you got.
If you are trying to return a list of the values of those 3 if's, then you should use the list function.
Related
The following Scheme code works fine:
(define (same-parity x . numbers-input)
(define (check-parity a) (= (remainder x 2) (remainder a 2)))
(define (iter numbers-left)
(cond ((null? numbers-left) nil)
((check-parity (car numbers-left)) (cons (car numbers-left) (iter (cdr numbers-left))))
(else (iter (cdr numbers-left)))))
(cons x (iter numbers-input)))
It is supposed to output a list with the first element being an integer x and the subsequent elements being all the integers from numbers-input which have the same parity as x.
If anyone is interested, this is my attempt at solving the exercise 2.20 from the book Structure and Interpretation of Computer Programs.
Now, I wanted to replace (car numbers-left) and (cdr numbers-left) with the variables "first" and "rest".
(define (same-parity x . numbers-input)
(define (check-parity a) (= (remainder x 2) (remainder a 2)))
(define (iter numbers-left)
(let ((first (car numbers-left))
(rest (cdr numbers-left)))
(cond ((null? numbers-left) nil)
((check-parity first) (cons first (iter rest)))
(else (iter rest)))))
(cons x (iter numbers-input)))
Trying to call this function now gives me an error:
> (same-parity 1 2 3 4 5)
. . mcar: contract violation
expected: mpair?
given: ()
Racket is highlighting the (car numbers-left) inside of the let-statement. Even when I never actually call "first" or "rest" in the body of the function and just leave it the way it was before, I get the same error.
However, in the following code I tried to copy the structure of the above procedure in a simple test definition and surprisingly, this works as you would expect.
(define (test x . testlist)
(define (test2 test2list)
(let ((first (car test2list)))
first))
(test2 testlist))
> (test 1 2 3 4 5)
2
It turns out that if I replace my (cond ...) in my original program with a simple call it works fine as well, so somehow the (cond ...) statement prohibits me from using the variables.
I know this is a very specific thing and I don't know if this ever really matters (except maybe if you want to make the code more readable) but I would really like to know why exactly it behaves this way.
Any insight would be appreciated!
Variables' values are evaluated as soon as you define them, whether you use them or not. Therefore you are calling (car '()) at the end of your recursion, once the list has become empty. You never make it to the part of your cond that attempts to exit.
(define (getFirstFew lst)
(cond
((= (read) 0) '()) ;returns nothing
(else(cons (car lst)(getFirstFew (cdr lst)(- (read) 1))))))
That is my code above. So i'm trying to write a procedure that will get the first x elements (user gets to choose what x gets to be) from a list. For example, input 4 with (getFirstFew '(1 6 2 4 5)) will result in '(1 6 2 4).
My current problem with this is that with using read two times, it gets called twice and then breaks the program. Is there a way for me to store whatever the user inputs into a variable and then use that variable throughout the program? Or is there another solution to this problem?
Notice that you have to perform the read only once, and store the value for future reference. Normally we'd use a let for this, but given that we also have to iterate over the list and decrement x on each iteration, a named let will be more appropriate. Try this:
(define (getFirstFew lst)
(let loop ((lst lst) (x (read)))
(if (= x 0)
'()
(cons (car lst)
(loop (cdr lst) (- x 1))))))
It works as expected:
(getFirstFew '(1 6 2 4 5))
> 4
=> '(1 6 2 4)
I'm looking at Scheme (Dr-Scheme) coming from Clojure.
In Clojure I can type
(print 'a 'b 'c)
and the print function figures out that this is an arbitrary number of non-string arguments and prints them out separated by a space.
In Scheme the print function expects a single argument.
Is there a way to get the equivalent of Clojure's print function in Scheme?
Interesting... you can roll one of those pretty easily, but I'm not sure I see the need for it. For instance:
#lang racket
(define (print-many . args)
(display
(apply
string-append
(add-between (map print-to-string args) " "))))
(define (print-to-string arg) (format "~v" arg))
(print-many 3 4 5 'b '(3 3 4))
In general, though, I'm thinking that if you're generating output for a user, you're going to want better control over the output, and if you're not generating output for a user, you're just as happy slapping a pair of parens around it and making it into a list.
What's the use case for this?
Perhaps you are looking for trace ?
#lang racket
(define (foo x y)
(+ x y))
(define (bar x)
(+ (foo 1 x)
(foo 2 (+ x 1))))
(require racket/trace)
(trace foo)
And then in the interaction window:
> (bar 3)
>(foo 1 3)
<4
>(foo 2 4)
<6
10
I use this set of definitions to print multiple arguments separated by new line:
(define (println x) (display x) (newline))
(define (printlist l) (begin
(println (car l))
(if (not (null? (cdr l))) (printlist (cdr l)))))
(define (multiprint . args) (begin
(if (not (null? args)) (printlist args)
(println "Error: multiprint requires at least one argument"))))
I am trying to write a simple procedure in Lisp to insert an element into binary search tree.
I represented the tree as a list:
the first element in the tree is the root
the second element is the left sub-tree
the third element is the right sub-tree
This is my code:
(define Insert
(lambda (x T)
(if (null? T)
(list x '() '())
(if (> x (car T))
(list (car T)
(cadr T)
(Insert x (list (caddr T))))
(list (car T)
(Insert x (cadr T))
(list (caddr T)))))))
When I call the procedure like this: (Insert 2 '(4 '(2 '() '() ) '())), I get a problem with ">" because the second argument isn't a real number, but I don't know why.
The exception:
>: expects type <real number> as 2nd argument, given: quote; other arguments were: 2
However, when I call the procedure like this: (Insert 2 ( list 4 (list 2 '() '() ) '())),
it works successfully.
Why?
I know that '(1 '() '()) and (list 1 '() '()) are equals, aren't they?
No, quote and list are not the same at all. The meaning of 'foo is (quote foo).
'(a b c) is exactly (quote (a b c)), that is, a list literal (the quote operator prevents the list from being evaluated). It is comparable to "a b c", which is a string literal or 5, which is a number literal. Operations that modify literals have undefined effects, as you may recognize immediately when you see some nonsense like (setf 3 4).
(list a b c), on the other hand, creates ("conses") a new list from the values of a, b, and c.
I am sure that if you clear up your confusion about quote and list, you will be able to correct your code.
'(1 '()) is equivalent to (list 1 (list 'quote nil)). I suspect that if you drop the "internal" quote characters, you will be fine.
So, the quoted expression that generates an expression that is equal to (list 1 '() '()) is '(1 () ()).
I am trying to learn lisp, using emacs dialect and I have a question.
let us say list has some members, for which predicate evaluates to false. how do I create a new list without those members? something like { A in L: p(A) is true }. in python there is filter function, is there something equivalent in lisp? if not, how do I do it?
Thanks
These functions are in the CL package, you will need to (require 'cl) to use them:
(remove-if-not #'evenp '(1 2 3 4 5))
This will return a new list with all even numbers from the argument.
Also look up delete-if-not, which does the same, but modifies its argument list.
If you manipulate lists heavily in your code, please use dash.el modern functional programming library, instead of writing boilerplate code and reinventing the wheel. It has every function to work with lists, trees, function application and flow control you can ever imagine. To keep all elements that match a predicate and remove others you need -filter:
(-filter (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (3 4 5)
Other functions of interest include -remove, -take-while, -drop-while:
(-remove (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (1 2)
(-take-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (1 2)
(-drop-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (3 2 1)
What is great about dash.el is that it supports anaphoric macros. Anaphoric macros behave like functions, but they allow special syntax to make code more concise. Instead of providing an anonymous function as an argument, just write an s-expression and use it instead of a local variable, like x in the previous examples. Corresponding anaphoric macros start with 2 dashes instead of one:
(--filter (> it 2) '(1 2 3 4 5)) ; (3 4 5)
(--remove (> it 2) '(1 2 3 4 5)) ; (1 2)
(--take-while (< it 3) '(1 2 3 2 1)) ; (1 2)
(--drop-while (< it 3) '(1 2 3 2 1)) ; (3 2 1)
I was looking for the very same last night and came across the Elisp Cookbook on EmacsWiki. The section on Lists/Sequences contains filtering teqniques and show how this can be done with mapcar and delq. I had to mod the code to use it for my own purposes but here is the original:
;; Emacs Lisp doesn’t come with a ‘filter’ function to keep elements that satisfy
;; a conditional and excise the elements that do not satisfy it. One can use ‘mapcar’
;; to iterate over a list with a conditional, and then use ‘delq’ to remove the ‘nil’
;; values.
(defun my-filter (condp lst)
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))
;; Therefore
(my-filter 'identity my-list)
;; is equivalent to
(delq nil my-list)
;; For example:
(let ((num-list '(1 'a 2 "nil" 3 nil 4)))
(my-filter 'numberp num-list)) ==> (1 2 3 4)
;; Actually the package cl-seq contains the functions remove-if and remove-if-not.
;; The latter can be used instead of my-filter.
Emacs now comes with the library seq.el, use seq-remove.
seq-remove (pred sequence)
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."
With common lisp, you can implement the function as follows:
(defun my-filter (f args)
(cond ((null args) nil)
((if (funcall f (car args))
(cons (car args) (my-filter f (cdr args)))
(my-filter f (cdr args))))))
(print
(my-filter #'evenp '(1 2 3 4 5)))
There are a ton of ways to filter or select stuff from a list using built-ins which are much faster than loops. The built-in remove-if can be used this way. For example, suppose I want to drop the elements 3 through 10 in list MyList. Execute the following code as an example:
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(and (>= Index 3) (<= Index 5))
)
MyList
)
)
You will get '(0 1 2 6 7 8 9).
Suppose you want to keep only elements between 3 and 5. You basically flip the condition I wrote above in the predicate.
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(or (< Index 3) (> Index 5))
)
MyList
)
)
You will get '(3 4 5)
You can use whatever you need for the predicate that you must supply to remove-if. The only limit is your imagination about what to use. You can use the sequence filtering functions, but you don't need them.
Alternatively, you could also use mapcar or mapcar* to loop over a list using some function that turns specific entries to nil and the use (remove-if nil ...) to drop nils.
It's surprising there's no builtin version of filter without cl or (or seq which is very new).
The implementation of filter mentioned here (which you see in the Elisp Cookbook and elsewhere) is incorrect. It uses nil as a marker for items to be removed, which means if you have nils in your list to start with, they're going to be removed even if they satisfy the predicate.
To correct this implementation, the nil markers need to be replaced with an uninterred symbol (ie. gensym).
(defun my-filter (pred list)
(let ((DELMARKER (make-symbol "DEL")))
(delq
DELMARKER
(mapcar (lambda (x) (if (funcall pred x) x DELMARKER))
list))))