I'm pretty new to racket and I'm trying to make a finite state machine for a project. here's what I have so far.
#lang racket
(define (test rules cs pass lst)
(if (eq? (length lst) 0)
(if (member cs pass)
(write 'passed)
(write 'failed))
(test rules (next rules cs (car lst)) (cdr lst))))
(define (next rules cs input)
(if (eq? cs (car (car rules)))
(if (eq? input (car(cdr(car rules))))
(car(cdr(cdr(car rules))))
((next (cdr rules) cs input)))
(next (cdr rules) cs input)))
then I input
(define rules '('(0 a 0) '(0 b 1) '(1 a 0) '(1 b 1)))
(define pass '(1))
(test rules 0 pass '(a b a b))
and for a reason that I cannot figure out, I get
this error on the next function. It acts as though rules is an empty list, which I'm pretty sure it's not. Anyway if anyone could tell me why it's doing that it would really help.
Thanks!
EDIT1
Thanks so much for the help guys. It's really helping. The code is working entirely until the end, but now it throws an error at the end of my code if I test multiple lists with testmany.
(define (testmany rules cs pass lst)(if (eq? (length lst) 0)
(write 'done)
((test rules cs pass (car lst))
(testmany rules cs pass (cdr lst)))))
(define (test rules cs pass lst) (if (eq? (length lst) 0)
(if (member cs pass)
(write 'accepted.....)
(write 'rejected.....))
(test rules (next rules cs (car lst)) pass (cdr lst))))
(define (next rules cs input) (if (eq? cs (car (car rules)))
(if (eq? input (car(cdr(car rules))))
(car(cdr(cdr(car rules))))
(next (cdr rules) cs input))
(next (cdr rules) cs input)))
The code doesn't seem to know when to stop the recursion of the testmany function. When the list is empty, it prints done, but then continues the next part as if the list still had elements, throwing this error. If anyone knows why it is throwing this error please let me know.
Thanks!
You forgot the begin:
(define (testmany rules cs pass lst) (if (eq? (length lst) 0)
(write 'done)
(begin
; ^^^^^ here
(test rules cs pass (car lst))
(testmany rules cs pass (cdr lst)))))
Without it, the return value of (test rules cs pass (car lst)) is attempted to be used as a function; but it is #<void>, the result of (write ....) form, which is the last one evaluated (more like, executed) by your test function.
By the way, #<void> is not an empty list; it's more like a non-value.
edit: the reason it does recurse to the end (without the begin) is that to apply a function foo in (foo val) to a value val, both expressions are evaluated first.
It is only after the evaluation of val, i.e. (testmany ...), finishes fully that the error is discovered that the value of foo, i.e. (test ...) expression, is not in fact a function, and can not be applied.
Related
Learning some Scheme/Racket, so give me some leeway.
Currently trying to find the max value when given a list without using the built-in max() function.
Current Code:
#lang racket
(provide max-num)
(define (max-num lst)
(define (helper lst max)
(displayln lst)
(displayln max)
(displayln " ")
(when (null? max) ; first run
(helper (cdr lst) (car lst)))
(if (null? lst)
max ; then end
(if (> (car lst) max) ; else compare
(helper (cdr lst) (car lst)) ; then update max
(helper (cdr lst) max)))) ; else keep max
(if (null? lst)
#f ; then Error
(helper lst '())) ; else run helper
)
(max-num '())
(max-num '(1 5 2 4 3))
Output via DrRacket:
As far as I can tell, the displayln outputs tell me I am on the right track. However, it ends up with a contract violation real? error instead of returning the max value.
I'm guessing that the (if (null? lst)) doesn't want to return "max" at the end and instead pushes towards the else branch despite the list being empty. I've looked around and debugged for about an hour now to no avail. Any help would be greatly appreciated.
You have to know that when you do:
(when test
do-something)
do-something-else
It will always do-something-else regardless if test is true or not. SO what is happening is that the first round max is null? and it does (helper (cdr lst) (car lst))) and that returns the answer. Then it discard that answer and continue to the if with max being null? and it finally fails when it does (> (car lst) max) since a null? is not a number. The error message says it expected a real? but it got the initial value '().
So to hint you on your way you should have one expression in addition to the local definitions eg.
(if test1
result1
(if test2
result2
alternative2))
or
(cond (test1 result1)
(test2 result2)
(else alternative2))
And of course since you know the argument is not null? you could just call (helper (cdr lst) (car lst)) instead of passing the empty list and remove the when entirely. when and unless are for side effects and not really for good functional Scheme style.
I am writing a program in Scheme and having difficulty with this one part. Below is an example to make my question clear
(endsmatch lst) should return #t if the first element in the list is the same as the last element in the list and return #f otherwise.
For example:
(endsmatch '(s t u v w x y z)) should return: #f
and
(endsmatch (LIST 'j 'k 'l 'm 'n 'o 'j)) should return: #t
Here is what I have so far (just error handling). The main issue I am having is solving this recursively. I understand there are easier solutions that are not recursive but I need to solve this using recursion.
My code so far:
(define (endsmatch lst)
(if (not(list? lst))
"USAGE: (endsmatch [list])"
(if (or (null? lst)
(= (length lst) 1))
#t
(equal? ((car lst)) (endsmatch(car lst)))
)))
I believe my code starting at "(equal? " is where it is broken and doesn't work. This is also where I believe recursion will take place. Any help is appreciated!
Easiest way is to use a (recursive) helper function to do the looping:
(define (endsmatch lst)
(define (helper no1 lst)
(if (null? (cdr lst))
(equal? no1 (car lst))
(helper no1 (cdr lst))))
(if (or (not (list? lst)) (null? lst))
"USAGE: (endsmatch [list])"
(helper (car lst) lst)))
The reason I pass lst and not (cdr lst) as the second argument in the last line is so that it also works for 1-element lists.
I tend to use KISS when programming. aka. "Keep it simple, stupid!"
With that regard I would have oped for:
(define (ends-match? lst)
(or (null? lst)
(equal? (car lst)
(last lst))))
Now last we can define like this:
(define (last lst)
(foldl (lambda (e a) e) last lst))
It's not perfect. It should signal an error if you pass an empty list, but in the ends-match? you check for this and thus it's not a problem.
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.
(define (walk-list lst fun) ;;walk-list(list, fun)
(if (not(null? lst)) ;;IF the list isn't NULL
(begin
(if (list? lst) ;;&& the list is actually a list , THEN{
(begin
(if (equal? (car lst) '()) ;;IF the first element in the list is empty
(fun lst) ;;THEN call the function on the list (funct is supose to get each word)
(if (not (null? lst)) ;;ELSE IF the first item isn't a list
(begin ;;{
(walk-list (car lst) fun) ;;walk-list((car lst),fun)
(walk-list (cdr lst) fun))))))))) ;;walk-list((cdr lst),fun)
(walk-list test-document display) ;;walk through the list with the given document
The will look something like this:
(define test-document '(
((h e l l o));;paragraph1
((t h i s)(i s)(t e s t));;paragraph2
))
I'm trying to get each individual word into the document have a function applied to it. Where is says (fun list). But the function is never called.
First off. begin is if you need to do more than one expression. The first expression then needs to have side effects or else it's just a waste of processing power.
Ie.
(begin
(display "hello") ; display is a side effect
(something-else))
When you don't have more than one expression begin isn't needed. if has 3 parts. They are:
(if predicate-expression ; turnas into something true or #f (the only false value)
consequent-expression ; when predicate-expression evalautes to anything but #f
alternative-expression) ; when predicate-expression evaluates to #f this is done
You should ident your code properly. Here is the code idented with DrRacket IDE, with reduncant begin removed and missing alternative-expressions added so you see where they return:
(define (walk-list lst fun) ;;walk-list(list, fun)
(if (not (null? lst)) ;;IF the list isn't NULL
(if (list? lst) ;; && the list is actually a list , THEN{
(if (equal? (car lst) '()) ;; IF the first element in the list is empty
(fun lst) ;; THEN call the function on the list (funct is supose to get each word)
(if (not (null? lst)) ;; ELSE IF the first item isn't a list
(begin ;; Here begin is needed
(walk-list (car lst) fun) ;; walk-list((car lst),fun)
(walk-list (cdr lst) fun)) ;; walk-list((cdr lst),fun)
'undfined-return-1)) ;; stop recursion, return undefined value
'undefined-return-2) ;; stop recursion, return undefined value
'undefined-return-3)) ;; stop recursion, return undefined value
So when does (fun lst) get called? Never! There is no () in any car in (((h e l l o))((t h i s) (i s) (t e s t))) and (equal? (car lst) '()) which is (null? (car lst)) will always be #f. Since we know (not (null? lst)) is #t so it will walk car and cdr where either 'undefined-return-2 or 'undefined-return-3 will be evaluated and the procedure stops when everything is visited and nothing processed.
You haven't shown what (walk-list test-document display) should have displayed but I make a wild guess that you want it for every element except pairs and null, thus I would have written this like this:
(accumulate-tree test-document display (lambda (a d) 'return) '())
accumulate-tree you'll find in this SICP handout. It demonstrates many uses for it as well. For completeness I'll supply it here:
(define (accumulate-tree tree term combiner null-value)
(cond ((null? tree) null-value)
((not (pair? tree)) (term tree))
(else (combiner
(accumulate-tree (car tree)
term
combiner
null-value)
(accumulate-tree (cdr tree)
term
combiner
null-value)))))
Judging from you code you are an Algol programmer learning your first Lisp. I advice you to look at the SICP videoes and book.
I've got a program I'm writing for a class to substitute the left-most occurrence of a variable with a new variable. (It actually allows you to provide an equivalence relation yourself, as well). The thing is, in Chez Scheme 8.2, this substitutes the right-most occurrence, if the left most is inside a list. We use a server running some version of scheme (I'm not sure which version), and on the server it substitutes, correctly, the left-most occurrence. Below is the code:
(define subst-leftmost
(lambda (new old ls proc)
(let ([keep-going? #t])
(letrec ([helper
(lambda (ls)
(cond [(null? ls) ls]
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
[(and keep-going? (proc old (car ls)))
(set! keep-going? #f) (cons new (cdr ls))]
[else (cons (car ls) (helper (cdr ls)))]))]) (helper ls))))
This is called like so: (subst-leftmost 'x 'a '(d b c (a) b a) eq?) which should produce the output (d b c (x) b a), and does on the server. In Chez scheme, however, it produces (d b c (a) b x). I think the difference is due to the line
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
evaluating the helper of the car and the helper of the cdr in a not-set order.
My question is this: Which version of scheme is following the standard, and how can I modify my code so that it works correctly in both versions?
(I've already talked to my professor about this. He's going to address the class about it on Monday, once he can think about it some, but I'm curious. I also already got the full points for the assignment, so don't worry about the ethics of helping me, in that regard.)
There isn't any, sorry. Here's the relevant legalese. Use LETs or LET* if you need to evaluate sub-expressions in a particular order.
Scheme guarantees no specific order (as Cirno has said). If your code has no side-effects, this doesn't matter.
However, your code is side-effecting (because of the set! to an outside variable), so, you have some choices:
Use Racket (which is committed to using left-to-right order, last time I talked to a Racket dev)
Structure your code to remove side-effects, so that your helper function doesn't change any variable or state outside it
Use appropriate lets to ensure the ordering you need (as Cirno suggested); in particular, change (cons (helper (car ls)) (helper (cdr ls))) to:
(let ((depth-first (helper (car ls))))
(cons depth-first (helper (cdr ls))))