I am trying to detect the palindrome lists in scheme. Here is my code:
;- Input : Takes only one parameter named inSeq
;- Output : It returns the reverse of inSeq if inSeq is a sequence.
; Otherwise it produces an error.
;- Examples :
; (reverse-sequence '(a b c)) --> evaluates to (c b a)
; (reverse-sequence '()) -------> evaluates to ()
(define reverse-sequence
(lambda (inSeq)
(if (sequence? inSeq)
(if (null? inSeq)
inSeq
(append (reverse-sequence (cdr inSeq))
(list (car inSeq)))))))
;- Input : Takes only one parameter named inSeq
;- Output : It returns true if inSeq is a sequence and it is a palindrome.
; It returns false if inSeq is a sequence but not a plaindrome.
; Otherwise it gives an error.
;- Examples :
; (palindrome? '(a b a)) --> evaluates to true
; (palindrome? '()) -------> evaluates to true
; (palindrome? '(a 1 a)) --> produces an error
(define palindrome
(lambda (inSeq)
(if (sequence? inSeq)
(if (equal? reverse-sequence(inSeq) inSeq )
#t
#f))))
When i try the input '(a b a) i get the following error:
The object (a b a) is not applicable
Can anyone help me with this error? Thanks
You wrote
(equal? reverse-sequence(inSeq) inSeq )
which tries to call (inSeq) as a function of no arguments. It should read:
(equal? (reverse-sequence inSeq) inSeq )
Remember, in Scheme the correct way to invoke procedure f on argument x is: (f x). That explains why this snippet doesn't work:
reverse-sequence(inSeq)
It should have been:
(reverse-sequence inSeq)
Be aware that you'll run into trouble if the argument received isn't a sequence, you'll get a void value and you won't get a correct answer. Also, you could have used the built-in reverse procedure, but I guess you want to implement it yourself - with that in mind, it'd be a better idea to reverse the list accumulating the result in a parameter (tail recursion), so you don't have to append the results (which is expensive), just cons the results (which is very cheap). This is what I mean:
(define (reverse-sequence inSeq)
(if (not (sequence? inSeq))
'() ; can't reverse if it's not a sequence
(let loop ((inSeq inSeq)
(reversed '()))
(if (null? inSeq)
reversed
(loop (cdr inSeq) (cons (car inSeq) reversed))))))
(define (palindrome inSeq)
(if (not (sequence? inSeq))
#f
(equal? inSeq (reverse-sequence inSeq))))
Related
I found this Scheme code on the internet, it outputs all subsets given a list, can someone explain how it works?
(define (subsets s) (if (null? s)
(list ())
(let ((rest (subsets (cdr s))))(append rest (map (lambda (x) (cons (car s) x)) rest)))))
(subsets '(a b c))
You really need to format it:
(define (subsets s)
(if (null? s)
(list ())
(let ((rest (subsets (cdr s))))
(append rest
(map (lambda (x)
(cons (car s) x))
rest)))))
What it does is return (()) for the argument '()
For a one element argument eg. '(b) if binds rest to the subsets of every element execept the first.. Which is no elements so rest is (()) and then it returns a list consisting of all the elements in rest as well as each list element of rest with b added to front. Thus (() (b)).
For a two element argument eg. '(a b) it binds rest to the subsets of every element except the first. Which is (b) so we know from above that it is (() (b)) and we know it will use those as well as every element with a added to the beginning: (() (b) (a) (a b))
I could go on but I'm guessing you get the picture?
I'm working through a textbook on programming languages, and one of the exercises was to make a function in Scheme that flips tuples in a list. Here's my code:
; invert : Listof(List(Int,Int)) -> Listof(List(Int,int))
; usage: (invert '((a 1) (a 2) (1 b) (2 b))) -> ((1 a) (2 a) (b 1) (b 2))
(define invert
(lambda (lst)
(if (null? lst)
'()
(cons
(flip (car lst))
(invert (cdr lst))))))
; flip : List(Int,Int) -> List(Int,int)
; usage: (flip '(a 1)) -> (1 a)
(define flip
(lambda (tuple)
(if (not (eqv? (length (tuple)) 2))
(eopl:error 'flip
"Tuple is not length 2~%")
(cons (cdr tuple) (car tuple)))))
I tried testing my program in chez-scheme. When I use the test case in the usage comment, I get this error: Exception: attempt to apply non-procedure (a 1). I've never worked with Scheme before, so I'd greatly appreciate any help and advice. Thanks!
You have a coupe of errors in flip, this should fix them:
(define flip
(lambda (tuple)
(if (not (= (length tuple) 2))
(eopl:error 'flip "Tuple is not length 2~%")
(list (cadr tuple) (car tuple)))))
In particular:
The specific error reported was because of this expression: (tuple). We must not surround variables with (), unless they're procedures that we intend to call.
We should use = for comparing numbers, not eqv?.
In this expression: (cons (cdr tuple) (car tuple)) there are two issues, for building a list of two elements we use list, not cons. And for accessing the second element we use cadr, not cdr - you should read a bit about how cons, car and cdr are used for building lists.
Notice that there's a simpler way to solve this problem if we use map; I'll skip error checking for simplicity:
(define (invert lst)
(map (lambda (tuple) (list (cadr tuple) (car tuple)))
lst))
Working on CLISP in Sublime Text.
Exp. in CLISP : less than 1 year
It's already for a while that I'm trying to solve this exercice... without success... as you might guess.
In fact I have to create a function which will modify the list and keeps only sublists which are equals or greater than the given number (watch below)
The list on which I have to work :
(setq liste '((a b) c (d) (e f) (e g x) f))
I'm supposed to find this as result :
(lenght 2 liste) => ((a b) (e f) (e g x))
liste => ((a b) (e f) (e g x))
Here my code :
(defun lenght(number liste)
(cond
((atom liste) nil)
((listp (car liste))
(rplacd liste (lenght number (cdr liste))) )
((<= (lenght number (car liste)) number)
(I don't know what to write) )
((lenght number (cdr liste))) ) )
It will be very kind if you could give me only some clue so as to let me find the good result.
Thanks guys.
Modifying the list does not make much sense, because it gets hairy at the head of the list to retain the original reference. Return a new list.
This is a filtering operation. The usual operator in Common Lisp for that is remove-if-not (or remove-if, or remove, depending on the condition). It takes a predicate that should return whether the element should be kept. In this case, it seems to be (lambda (element) (and (listp element) (>= (length element) minlength))).
(defun filter-by-min-length (minlength list)
(remove-if-not (lambda (element)
(and (listp element)
(>= (length element) minlength)))
list))
In many cases, when the condition is known at compile time, loop produces faster compiled code:
(defun filter-by-min-length (minlength list)
(loop :for element :in list
:when (and (listp element)
(>= (length element) minlength))
:collect element))
This returns a new list that fulfills the condition. You'd call it like (let ((minlength-list (filter-by-min-length 2 raw-list))) …).
Many basic courses insist on recursively using primitive operations on cons cells for teaching purposes at first.
The first attempt usually disregards the possible stack exhaustion. At each step, you first look whether you're at the end (then return nil), whether the first element should be discarded (then return the result of recursing on the rest), or if it should be kept (then cons it to the recursion result).
If tail call optimization is available, you can refactor this to use an accumulator. At each step, instead of first recursing and then consing, you cons a kept value onto the accumulator and pass it to the recursion. At the end, you do not return nil, but reverse the accumulator and return that.
Well, I have found the answer that I was looking for, after scratching my head until blood...
Seriously, here is the solution which is working (and thanks for the correction about length which helped me to find the solution ^^) :
(defun filter-by-min-length (min-length liste)
(cond
((atom liste) nil)
((and (listp (car liste))(>= (length (car liste)) min-length))
(rplacd liste (filter-by-min-length min-length (cdr liste))) )
((filter-by-min-length min-length (cdr liste))) ) )
A non-modifying version
(defun filter-by-min-length (min-length le)
(cond ((atom le) nil)
((and (listp (car le)) (>= (length (car le)) min-length))
(cons (car le) (filter-by-min-length min-length (cdr le))))
(t (filter-by-min-length min-length (cdr le)))))
Test:
(defparameter *liste* '((a b) c (d) (e f) (e g x) f))
(filter-by-min-length 2 *liste*)
;; ((A B) (E F) (E G X))
*liste*
;; ((A B) C (D) (E F) (E G X) F) ; -> *liste* not modified
For building good habits, I would recommend to use defparameter instead of setq, since the behaviour of setq might not always be defined (see here). In the link, it is said:
use defvar, defparameter, or let to introduce new variables. Use setf
and setq to mutate existing variables. Using them to introduce new
variables is undefined behaviour
I'm totally new to Scheme and I am trying to implement my own map function. I've tried to find it online, however all the questions I encountered were about some complex versions of map function (such as mapping functions that take two lists as an input).
The best answer I've managed to find is here: (For-each and map in Scheme). Here is the code from this question:
(define (map func lst)
(let recur ((rest lst))
(if (null? rest)
'()
(cons (func (car rest)) (recur (cdr rest))))))
It doesn't solve my problem though because of the usage of an obscure function recur. It doesn't make sense to me.
My code looks like this:
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
I do understand the logic behind the functional approach when programming in this language, however I've been having great difficulties with coding it.
The first code snippet you posted is indeed one way to implement the map function. It uses a named let. See my comment on an URL on how it works. It basically is an abstraction over a recursive function. If you were to write a function that prints all numbers from 10 to 0 you could write it liks this
(define (printer x)
(display x)
(if (> x 0)
(printer (- x 1))))
and then call it:
(printer 10)
But, since its just a loop you could write it using a named let:
(let loop ((x 10))
(display x)
(if (> x 0)
(loop (- x 1))))
This named let is, as Alexis King pointed out, syntactic sugar for a lambda that is immediately called. The above construct is equivalent to the snippet shown below.
(letrec ((loop (lambda (x)
(display x)
(if (> x 0)
(loop (- x 1))))))
(loop 10))
In spite of being a letrec it's not really special. It allows for the expression (the lambda, in this case) to call itself. This way you can do recursion. More on letrec and let here.
Now for the map function you wrote, you are almost there. There is an issue with your two last cases. If the list is not empty you want to take the first element, apply your function to it and then apply the function to the rest of the list. I think you misunderstand what you actually have written down. Ill elaborate.
Recall that a conditional clause is formed like this:
(cond (test1? consequence)
(test2? consequence2)
(else elsebody))
You have any number of tests with an obligatory consequence. Your evaluator will execute test1? and if that evaluated to #t it will execute the consequence as the result of the entire conditional. If test1? and test2? fail it will execute elsebody.
Sidenote
Everything in Scheme is truthy except for #f (false). For example:
(if (lambda (x) x)
1
2)
This if test will evaluate to 1 because the if test will check if (lambda (x) x) is truthy, which it is. It is a lambda. Truthy values are values that will evaluate to true in an expression where truth values are expected (e.g., if and cond).
Now for your cond. The first case of your cond will test if L is null. If that is evaluated to #t, you return the empty list. That is indeed correct. Mapping something over the empty list is just the empty list.
The second case ((f (car L))) literally states "if f is true, then return the car of L".
The else case states "otherwise, return the result mymap on the rest of my list L".
What I think you really want to do is use an if test. If the list is empty, return the empty list. If it is not empty, apply the function to the first element of the list. Map the function over the rest of the list, and then add the result of applying the function the first element of the list to that result.
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
So what you want might look look this:
(define (mymap f L)
(cond ((null? L) '())
(else
(cons (f (car L))
(mymap f (cdr L))))))
Using an if:
(define (mymap f L)
(if (null? L) '()
(cons (f (car L))
(mymap f (cdr L)))))
Since you are new to Scheme this function will do just fine. Try and understand it. However, there are better and faster ways to implement this kind of functions. Read this page to understand things like accumulator functions and tail recursion. I will not go in to detail about everything here since its 1) not the question and 2) might be information overload.
If you're taking on implementing your own list procedures, you should probably make sure they're using a proper tail call, when possible
(define (map f xs)
(define (loop xs ys)
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys))))
(loop (reverse xs) empty))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)
Or you can make this a little sweeter with the named let expression, as seen in your original code. This one, however, uses a proper tail call
(define (map f xs)
(let loop ([xs (reverse xs)] [ys empty])
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys)))))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)
Define a procedure encrypt that takes three strings: a message to be encrypted and two alphabets, which we will call regular and encrypted. The alphabet strings are both the same length and they do not contain duplicates. For each character in the message, look it up in regular and, if you find it, convert it to the character in the corresponding location of encrypted. For example, if the regular is abc and the encrypted is def, that means that an a in the message will encode as a d, a b encodes as an e, and a c encodes as an f.
i wrote my code as follow:
(define encrypt
(lambda (message regular encrypted)
(define help
(lambda (ls1 ls2 ls3)
(if (null? ls1) '()
(if (and (null? ls2) (null? ls3)) ls1
(if (equal? (car ls1) (car ls2))
(cons (car ls3) (help (cdr ls1) ls2 ls3))
(help ls1 (cdr ls2) (cdr ls3))))))
(list->string (help
(string->list message)
(string->list regular)
(string->list encrypted)))))
I have been trying to get a running. but the result returns Exception in car: () is not a pair
I quite check it many times, but I didn't what I should change. is there anyone can help me?
Óscar López's answer pointed out some of the problems that you might be having in this code, but I think it's important to specifically address the error message that you mentioned: () is not a pair. This means that you're calling a function that expects a pair (so typical candidates would be car and cdr on an empty list. Let's take a look at your code and see where this could happen:
(define help
(lambda (ls1 ls2 ls3)
(if (null? ls1) '() ; a
(if (and (null? ls2) (null? ls3)) ls1 ; b
(if (equal? (car ls1) (car ls2)) ; c
(cons (car ls3) (help (cdr ls1) ls2 ls3)) ; d
(help ls1 (cdr ls2) (cdr ls3)))))) ; e
Lines a and b don't call any functions that expect a pair, so you shouldn't run into this problem there.
In line c, you do (car ls1) and (car ls2). Line a ensured that ls1 isn't (), but ls2 still could be, since b only checked that it's not the case that both ls2 and ls3 are (); either one alone still could be.
In line d, you've got (car ls3) and (cdr ls1). Line a ensured that ls1 isn't (), but ls2 still could be for the same reason given in the previous case.
Line e has (cdr ls2) and (cdr ls3), and both of these could cause a problem, because either one of them (but not both) could be ().
Though your title didn't say it, your question mentioned that this is actually happening with car, which means that it's not happening in e, which leaves c and d. It's either happening in (car ls2) in c or in (car ls3) in d.
If you're using Dr. Racket to run your code, the IDE should highlight the place where the bad call happened (something like what's shown in the screenshot in this answer).
The help function is not doing what you imagine, you actually need two helpers:
One for iterating over the message and "encrypting" each character in it, for that it uses the next function as helper
And one for "encrypting" a single character, that takes care of finding the encrypted character corresponding to a plaintext character
If you don't do the above, you'll discover that not all the characters are being replaced, because you're traversing the regular/encrypted lists only once, but for the algorithm to work you have to traverse them once for each character in the input message.
(define (encrypt message regular encrypted)
(letrec ((key
(lambda (reg enc)
(if (null? reg)
'()
(cons (cons (car reg) (car enc))
(key (cdr reg) (cdr enc))))))
(keys (key (string->list regular)
(string->list encrypted))))
(list->string
(let loop ((message (string->list message)))
(if (null? message)
'()
(cons (cdr (assoc (car message) keys))
(loop (cdr message))))))))