,i am doing my assignment in Scheme. I am using Scheme MIT Interpreter and https://repl.it/languages/scheme to test my code.
First question is
; - in? procedure takes an element ‘el’ and a list ‘lst’.
; - It returns a boolean value.
; - When el is in lst it returns true, otherwise returns false.
; - Examples:
; (in? 3 ’(2 5 3))
; evaluates to #t
; (in? 2 ’(1 (2) 5))
; evaluates to #f
; - If lst is not a list, it produces an error..
my code is
(define lst())
(define el())
(define in? (lambda (el lst)
(if(null? lst)
#f
(if (eq? (car lst el ))
#t
(in? el cdr lst )))
(error "ERROR")))
(in? 3'(2 5 3))
I got error in MIT Interpreter below
The procedure #[compiled-procedure 13 ("global" #x14) #x14 #x2620cd4] has been called with 3 arguments; it requires exactly 2 arguments. ;To continue, call RESTART with an option number: ;
(RESTART 1) => Return to read-eval-print level 1.
and when i test it in https://repl.it/languages/scheme
i got error like
Error: 2 is not a function [(anon)]
Why i am getting these errors?
Try this:
(define in?
(lambda (el lst)
(if (or (null? lst) (pair? lst))
(if (null? lst)
#f
(if (equal? (car lst) el )
#t
(in? el (cdr lst))))
(error "ERROR"))))
The usual tips apply: be careful with the parentheses, indent correctly your code, use equal? for equality comparisons, notice the correct way to test if the parameter is a list and make sure you understand how to pass parameters to a procedure and how to actually call a procedure. It works as expected now:
(in? 1 '(2 5 3))
=> #f
(in? 3 '(2 5 3))
=> #t
(in? 1 5)
=> ERROR
Related
I wanted to make a procedure that destructively increments the odd numbers of a list. I thought I'd recurse through it and just use 'set-car!' whenever 'odd?' was true.
Here is the code:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
I'm not sure why it is not working, I guess I do not understand set-car! and set-cdr!
Could someone explain? Thank you.
The problem might be with your interpreter, or the language in which you're defining the procedure, or the way you're calling it. For instance, in DrRacket this works fine:
#lang r5rs
(define (test lst)
(cond ((null? lst) lst) ; this is the '() returned by the recursion
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
Bear in mind that your procedure will return an empty list, because that's the base case of the recursion and this is a tail-recursive procedure, which returns the value at the base case as its final result. But don't worry, the input list was modified in-place, you can check it after the procedure returns its value.
(define lst (list 1 2 3 4))
(display (test lst))
=> ()
(display lst)
=> (2 2 4 4)
See how mutability is confusing? a procedure is returning one value, but its input was modified and has a different value now. That's one of the reasons why functional programming (which favors immutable data) is cleaner and simpler to understand, and also demonstrates why is a bad idea to mutate input parameters inside a procedure ;)
If you absolutely want the procedure to return the mutated list, do as #sepp2k suggests, but remember - the input list was modified and in fact, is the same list that is returned as a result:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst))
lst) ; add this line
(else (test (cdr lst)))))
See for yourself:
(define lst (list 1 2 3 4))
(display (test lst))
=> (2 2 4 4)
(display lst)
=> (2 2 4 4)
was expecting the have the list containing (2 2 4 4) returned
The way you defined your function, it will return an empty list when called on the empty list and the result of the recursion in all other cases. So since the only base case is the empty list, you'll always return the empty list.
If you want to return the modified list, you'll need to do that after the recursion. That is after (test (cdr lst)), add lst to return the value of lst.
You are using set-car! correct. Here is how you tell it's working:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
(define test-list (list 1 2 3 4))
(test test-list)
test-list ; ==> (2 2 4 4)
Your expectation that the function will return the modified list is wrong. To do that you need the first recursion step to return the argument. You need to wrap it:
(define (inc-odds lst)
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
(inc-odds lst) ; do the stuff
lst) ; return the list
(inc-odds (list 1 2 3 4)) ; ==> (2 2 4 4)
(inc-odds '(1 2 3 4)) ; ==> "pigs flying"
Notice the last one. In the RNRS upto R5RS passing a quoted literal to set-car! would produce an undefined behaviour which means anything is ok because technically the code isn't Scheme. In R6RS it's required to raise an exception.
I'm attempting to write a scheme function that prints each entry of a list on a new line. This function and sample input works as expected, then gives an "illegal function" error and exits. I'm using tinyscheme from the debian repos.
(define print-list
(lambda (l)
(if (null? l)
(display "done\n")
(
(display (car l))
(newline)
(print-list (cdr l))
)
)
)
)
(print-list '(1 2 3 4 5) )
A parenthesis followed by an expression means function application.
(expr1 expr2 ...)
Means evaluate expr1, expr2, .... Then apply the result of expr1 to the result of expr2 ... . If the result of expr1 is not a function, then you'll see the "illegal function" error.
The fix is as leppie states to add a begin:
(define print-list
(lambda (l)
(if (null? l)
(display "done\n")
(begin
(display (car l))
(newline)
(print-list (cdr l))))))
(print-list '(1 2 3 4 5) )
Here
(begin expr1 expr2 ....)
means evalute expr1, expr2, ... in order. Finally return the value of the last expression.
Block Structure
In scheme, the branches of the if special form do not have an implicit block structure. As Soegaard suggests, begin may be used. Or you can use cond to create a block—in which case, expanding to more than two branches comes along for free.
(define (print-list a-list)
(cond ((null? a-list)(display "done\n"))
(else
(display (car a-list))
(newline)
(print-list (cdr a-list)))))
Problem with Return Type
Note that print-list is problematic because it returns...well something undefined. For example in MIT Scheme:
1 ]=> (print-list '(a b c))
a
b
c
done
;Unspecified return value
Or in Gauche Scheme:
gosh> (print-list '(a b c))
a
b
c
done
#<undef>
While in Racket's implementation of R5RS the return value is not printed.
> (print-list '(a b c))
a
b
c
done
Returning a Value
One common approach to signalling the end of a series of side effects is to return a value. null is one possibility. A symbol is another.
(define (print-list a-list)
(cond ((null? a-list) 'done) ; changed this line.
(else
(display (car a-list))
(newline)
(print-list (cdr a-list)))))
Calling it now will in a Scheme REPL removes the problematic return value:
gosh> (print-list '(a b c))
a
b
c
done
I know Scheme and other Lisp dialects include logical operators such as 'and' and 'or', but, since I am currently learning Scheme, I am trying to program my own logical operators. So far my attempts at 'or' have been successful (at least so far as my testing has shown me). My logical or operator is the following:
(define (logical-or a b)
(if a true b))
I am trying to program a logical operator for 'and' that also returns a boolean, but I keep getting stuck. I have tried any number of combinations, but I will just list the following one, which doesn't return a boolean:
(define (logical-and a b)
(if a b false))
Any hints or help welcome.
As Uselpa's answer and the leppie's comments mentioned, the operators and and or don't return #t but the value that was not #f that decided the outcome of the form. Thus
(and 'these 'are 'all 'true 'values) ; ==> values
(or 'these 'are 'all 'true 'values) ; ==> these
The logical operators and and or are short circuiting so they are not procedures. Imagine this procedure:
(define (first-true-value lst)
(and (pair? lst)
(or (car lst)
(first-true-value (cdr lst)))))
(first-true-value '()) ; ==> #f
(first-true-value '(#f #f)) ; ==> #f
(first-true-value '(#f #f hello)) ; ==> hello
If you replace and and or with your versions the procedure will never stop evaluating the recursion.
We know we can rewrite and with if. (and) is #t, (and a) is a and (and a b ...) is (if a (and b ...) #f). We could do this with th easiest Scheme macros, syntax-rules:
(define-syntax logical-and
(syntax-rules ()
((logical-and) #t)
((logical-and a) a)
((logical-and a b ...)
(if a (logical-and b ...) #f))))
We can also do or the same way. (or) is #f and (or a b ..) is (if a a (or b ...)):
(define-syntax logical-or
(syntax-rules ()
((logical-or) #f)
((logical-or a b ...) ; NB: zero elements match "b ..."
(if a a (logical-or b ...)))))
There is a problem with this one since it uses a twice.. Try (logical-or (display "hello")). It will evaluate (display "hello") and thus display the text twice. To fix this we need to wrap the value in a let:
(define-syntax logical-or
(syntax-rules ()
((logical-or) #f)
((logical-or a b ...)
(let ((tmp a))
(if tmp
tmp
(logical-or b ...))))))
If you try the same it will only display "hello" once. Lets try writing my initial procedure with the new macros:
(define (first-true-value lst)
(logical-and (pair? lst)
(logical-or (car lst)
(first-true-value (cdr lst)))))
;; and we test them:
(first-true-value '()) ; ==> #f
(first-true-value '(#f #f)) ; ==> #f
(first-true-value '(#f #f hello)) ; ==> hello
Your logical-or does not always return booleans either:
> (logical-or #f 2)
2
As #leppie says, anything not false (#f) is true in Scheme; try experimenting a little with the build-in or function:
> (or 1 2)
1
> (or #f 2)
2
> (or #t 2)
#t
> (or 1 #f)
1
> (or #f #t)
#t
so the definition in Scheme would be:
(define (my-or a b)
(if a a b))
Likewise, for and:
> (and 1 #t)
#t
> (and 1 #f)
#f
> (and 1 2)
2
> (and #f 2)
#f
> (and #t 2)
2
so the definition is
(define (my-and a b)
(if a b a))
If you want to only return booleans, then you'd code
(define (logical-or a b)
(cond
(a #t)
(b #t)
(else #f)))
(define (logical-and a b)
(if a
(if b
#t
#f)
#f))
This works for 2 values, but since the build-in and and or operators allow any number of parameters (even 0) and only evaluate their parameters if necessary the real definitions are a little more complicated.
You are given a list of strings.
Generate a procedure such that applying this procedure to such a list
would result in a list of the lengths of each of the strings in the
input.
Use map, filter, or fold-right.
(lengths (list "This" "is" "not" "fun")) => (4 2 3 3)
(define lengths (lambda (lst) your_code_here))
I got stuck in the following code and I do not understand how can I use filter.
(define lengths
(lambda (lst)
(if (null? lst)
nil
(fold-right list (string-length (car lst)) (cdr lst)))))
This seems like a work for map, you just have to pass the right procedure as a parameter:
(define (lengths lst)
(map string-length lst))
As you should know, map applies a procedure to each of the elements in the input list, returning a new list collecting the results. If we're interested in building a list with the lengths of strings, then we call string-length on each element. The procedure pretty much writes itself!
A word of advice: read the documentation of the procedures you're being asked to use, the code you're writing is overly complicated. This was clearly not a job for filter, although fold-right could have been used, too. Just remember: let the higher-order procedure take care of the iteration, you don't have to do it explicitly:
(define (lengths lst)
(fold-right (lambda (x a)
(cons (string-length x) a))
'()
lst))
This looks like homework so I'll only give you pointers:
map takes a procedure and applies to to every element of a list. Thus
(define (is-strings lst)
(map string? lst))
(is-strings '("hello" 5 sym "89")) ; (#t #f #f #t)
(define (add-two lst)
(map (lambda (x) (+ x 2)) lst))
(add-two '(3 4 5 6)) ; ==> (5 6 7 8)
filter takes procedure that acts as a predicate. If #f the element is omitted, else the element is in the resulting list.
(define (filter-strings lst)
(filter string? lst))
(filter-strings '(3 5 "hey" test "you")) ; ==> ("hey" "you")
fold-right takes an initial value and a procedure that takes an accumulated value and a element and supposed to generate a new value:
(fold-right + 0 '(3 4 5 6)) ; ==> 18, since its (+ 3 (+ 4 (+ 5 (+ 6 0))))
(fold-right cons '() '(a b c d)) ; ==> (a b c d) since its (cons a (cons b (cons c (cons d '()))))
(fold-right - 0 '(1 2 3)) ; ==> -2 since its (- 1 (- 2 (- 3 0)))
(fold-right (lambda (e1 acc) (if (<= acc e1) acc e1)) +Inf.0 '(7 6 2 3)) ; ==> 2
fold-right has a left handed brother that is iterative and faster, though for list processing it would reverse the order after processing..
(fold-left (lambda (acc e1) (cons e1 acc)) '() '(1 2 3 4)) ; ==> (4 3 2 1)
Write a procedure called direct-num-occurs? that checks whether a number occurs in a list of numbers. Examples:
> (direct-num-occurs? 1 '(2 3 1 4))
;=> #t
> (direct-num-occurs? 1 '(2 3 5 4))
;=> #f
This is what I tried:
(define direct-num-occurs?
(lambda (num ws)
(cond
[(null? ws) #f]
[(equal? num (car ws)) #t]
[else (direct-num-occurs? (cdr ws) num)])))
But I'm getting an error that says expected a pair.
For future reference, you're re-implementing the member procedure:
(define (direct-num-occurs? n lst)
(if (member n lst) #t #f))
... But I guess you're trying to write it from scratch. The implementation shown is basically correct, except that you passed the arguments in the wrong order in the last line. This should fix it:
(define direct-num-occurs?
(lambda (num ws)
(cond
[(null? ws) #f]
[(equal? num (car ws)) #t]
[else (direct-num-occurs? num (cdr ws))])))
Of course, it works as expected:
(direct-num-occurs? 1 '(2 3 1 4))
=> #t
(direct-num-occurs? 1 '(2 3 5 4))
=> #f