I’m working on a Scheme function that takes two words and checks to see if their lengths are the same. It should output 'same length' if they are and specify the longer and shorter string with their lengths if they don't have the same length.
So I tried
(define (strings x y)
(if (= (string-length x)(string-length y))
display "same length"
(string-length x)(string-length y)))
but it says that two string-lengths are the same length even if they aren't. It also only prints the string-length of x if I put parentheses on display "same length". I’m not sure how to go about fixing it.
How you have formatted code does not agree with what an IDE would do. Eg. pasting your code in DrRacket and pressing CTRL+i gives me:
(define (strings x y)
(if (not (= (strings-length x)(strings-length y))
(display "same length")) ; this is second argument to not
(if (> (strings-length x)(strings-length y))
((strings-length x)(strings-length y)))))
So the first if calls not with two arguments because you lack the closing parantesis on the end of the line. You also lack the else clause such that a false test leaves what the result is to the implementation.
Basically you are after this:
(if (= (string-length x) (string-length y))
what-to-do-when-true
what-to-do-when-false)
Notice you don't need the second if since you are testing the opposite of the first one and you are guaranteed to end up in the code what-to-do-when-false. Also notice I've removed the not so you just switch the order. If you'd like you can re-add the not, but don't forget the parentheses.
Related
I am looking to write a Scheme function numofatoms that determines the number of elements in a list.
For example, (numOfSymbols '((1 3) 7 (4 (5 2) ) ) should return 6.
What I have so far:
;(1 3) 7 (4(5 2)) the list
(define (numofatoms lst) ;defining a numofatoms function
(define (flatten x) ;defining a flatten function
(cond ((null? x) '())
((pair? x) (append (flatten (car x)) (flatten (cdr x))))
(else (list x))))
(length (flatten lst)))
(numofatoms '((1 3) 7 (4(5 2)))); calling the function
After defining numofatoms and flatten I don't see any errors but the program is not working. It doesn't produce any outputs.
The posted code works fine if you load it and call numofatoms from the REPL. I presume that OP is either calling load from the REPL or running the code as a script from the command-line, and when either of these is done OP sees no output. The REPL evaluates and prints results (hence the P), but when you load code that isn't necessarily what happens.
When an expression is evaluated in the REPL, the value to which the expression evaluates is printed. There may be an expectation that the value of the final expression in a file will be printed when the file is loaded into the REPL, but that expectation will not be rewarded.
The load procedure is not standardized for R6RS; here it is implementation-specific, and the particulars depend upon the implementation. For Chez Scheme, load returns an unspecified value, so there should be no expectation of seeing anything useful when a file is successfully loaded.
Both R5RS and R7RS have load procedures described in the standards, but both leave it unspecified whether the results of evaluating the expressions in a file are printed.
The details of any script mechanism for Scheme programs is entirely dependent upon the implementation. But, when you run a script from the command-line your are not in a REPL, so again there should be no expectation that the results of evaluating various forms in the file will be printed to the terminal window.
If you want a Scheme file or script to print something, you have to make it do that. If the final line of the posted file is changed to (display (numofatoms '((1 3) 7 (4(5 2))))) (newline), the program will display the result of calling numofatoms whenever it is run.
I'm triying to use when in Scheme but i dont know why at the last element of my list appears .#void>.
Here is my code
(define (genlist x y)
(when
(< x y)
(cons x (genlist (+ x 1) y))))
And this is my output =>
(2 3 4 5 6 7 8 9 . #void>)
We use when when we need to write an if without an else part, and/or when we need to write more than one expression inside the if. Only the last expression's value gets returned, hence we use it mostly for the side effects. To understand it better, in Racket this:
(when <condition>
<exp1>
<exp2>
<exp3>)
Is equivalent to this:
(if <condition>
(begin
<exp1>
<exp2>
<exp3>)
(void)) ; implementation-dependent
The same considerations apply to unless, except that the condition is surrounded with a (not ...).
The source of your problems (and the reason why it's a code smell to have an if without an else) is that your code is not handling the case when (>= x y). Ask yourself, what should you do in that case? Simple, return an empty list! that's the base case of the recursion that's missing from your code.
You would need to use (if (< x y) (cons ...) '()) to produce a proper list.
when (and it's counterpart unless) is mostly for doing side effects (like printing something out) in a context where the result is not used.
e.g. (when debug-mode? (print "got here"))
when is an one armed ifs with implicit begin. The following examples are the same:
(if (any odd? lst)
(begin
(set! some-binding #t)
(display "Found an odd element")))
(when (any odd? lst)
(set! some-binding #t)
(display "Found an odd element"))
And you can use unless instead of using not in the predicate:
(if (not (any odd? lst))
(set! some-binding #f))
(unless (any odd? lst)
(set! some-binding #f))
Peter Norvig made a nice book about Lisp style and in it he addresses this:
Be as specific as your data abstractions warrant, but no more.
if for two-branch expression
when, unless for one-branch statement
and, or for boolean value only
cond for multi-branch statement or expression
So while you can write all your logic using if it will not be the easiest code to read. Other might use the term principle of least surprise. Even though the book is for Common Lisp much of it can be used in Scheme as well. It's a good read if you want to program any lisp dialect professionaly.
For when and unless this is applies much better to Scheme as you have no idea what an implementation might return in the event the predicate evaluates to #f while in CL you could abuse when since it's destined to return nil in such cases.
In you code you are trying to return something and letting the implementation choose what should happen when the predicate failes is what causes the #<void>. When the return matter you should always use two armed if:
(if test-expression
then-expression
else-expression)
Note there is no else keyword.
I am following the SICP lectures from MIT, and this is what I tried to find the square root approximation of a number by Heron of Alexandria's method. This is my first time trying out lisp, sorry for making noobie mistakes.
(define guess 1)
(define (avg a b)
(/ (+ a b) 2))
(define (try guess x)
(if (goodEnough guess x)
guess
(improve guess x)))
(define (improve guess x)
(define guess (avg guess (/ x guess)))
(try guess x)
)
(define (goodEnough guess x)
(= guess (avg guess (/ x guess))))
(print (try 1 25))
I am using Chicken scheme compiler to print this. This is the output:
Error: (/) bad argument type: #<unspecified>
Call history:
1.a.SquareRootApproximation.scm:29: try
1.a.SquareRootApproximation.scm:17: goodEnough
1.a.SquareRootApproximation.scm:27: avg
1.a.SquareRootApproximation.scm:19: improve <--
Updated: I have changed my approach towards this problem using lisp with more abstraction, yet I can't figure out what this new error wants to imply. Any fixes? Thanks!
The value #<unspecified> is basically "void" in other languages. It is used as a return value whenever some procedure has nothing useful to return (for example, print will return this). It is also in some situations used as a temporary placeholder value, for example when handling an inner define.
Normally this temporary placeholder should not be visible to the user of the language, but it appears you've hit a strange edge case in the language (congratulations! This happens rarely). The error happens because (define guess (avg guess (/ x guess))) in the improve procedure is simultaneously defining a variable and using that variable. The behaviour of doing this is not well-specified, and some Scheme implementations will do what CHICKEN is doing (Guile, Gauche, Gambit) whereas others will give a somewhat more meaningful error message (MIT, Scheme48, Racket). The reason this is ill-specified has to do with the fact that inner define expands to letrec, because it allows mutually recursive procedures to be defined, but that creates a bit of an issue: what should happen for (define a b) (define b a), for example?
Your intention seems to be using the old guess variable that's passed as input to the procedure, so instead of using define you could use let to bind a new value for guess (how this should behave is well-specified), or just use a different name for it, like new-guess.
I am trying pass in a list input to conversation and have the function check to see if the first element in another list (keyword) matches to the first element of the list that user passed in. If the two match then output a zero otherwise pass the tail of the inputted list recursively back to itself.
(define keyword '(am I))
(define (conversation input)
(cond
((equal? (car keyword) (car input)) 0)
(else (conversation (cdr input)))))
The error I get is:
car: contract violation
expected: pair?
given: '()
I understand that equal? compares two elements, a pair, but what I do not understand is why it would create an error when the car of both lists are both exactly an element. Any help would be much appreciated, I'm assuming the solution is rather simple but I can't seem to see it.
My goal is create several functions that pattern match and output appropriate dialog but without the use of regular expressions or other libraries. There is no mandate not to use the two mentioned above but I would like to do it without them to get a better understanding of the logic and the code. Thanks for the help!
The first thing to consider is that you have no condition of failure. You assume there's either a match now with the car, or there will be a match later with the cdr. But there may be no match at all, and you will cdr down your list until your list is '(). As there is no such thing as the car of '() you are getting an error when you try to extract it. Therefore the first thing to do is make sure you've handled this case. I don't know what you intend to do in this case, so I have made the procedure return #f.
Next you consider what to do if the symbols do match. In your case you are choosing to return 0. This part seems to have no problems.
Finally, we consider what to do if the cars do not match. In this case we continue searching the input. This part seems to have no problems.
(define (conversation input)
(cond ((null? input) #f)
((eq? (car input) (car keyword))
0)
(else
(conversation (cdr input)))))
I try to implement a "special-if" that suppose to behave like regular "if" with cond. Here's the code:
(define (special-if pre act alt)
(cond (pre act)
(else alt)))
To test if this works, I wrote a factorial function with this "special-if":
(define (factorial n)
(special-if (= n 1)
1
(* n (factorial (- n 1)))))
However, when I evaluate (factorial 3), it runs forever. Seems the predicate part (= n 1) was never evaluated. Can anyone tell me why this won't work? Thanks.
Your special if is doomed to fail, I'm afraid. Remember: if is an special form with different evaluation rules (and cond is a macro implemented using if), that's why an expression like this runs fine even though it has a division by zero:
(if true 'ok (/ 1 0))
=> 'ok
... whereas your special-if will raise an error, because it's using the normal evaluation rules that apply for procedures, meaning that all its arguments get evaluated before executing the procedure:
(special-if true 'ok (/ 1 0))
=> /: division by zero
Now you see why your code fails: at the bottom of the recursion when n is 1 both the consequent and the alternative will execute!
(special-if (= 1 1)
1 ; this expression is evaluated
(* 1 (factorial (- 1 1)))) ; and this expression too!
... And factorial will happily continue to execute with values 0, -1, -2 and so on, leading to an infinite loop. Bottom line: you have to use an existing special form (or define a new macro) for implementing conditional behavior, a user-defined standard procedure simply won't work here.
You've heard why your special-if doesn't work, but you accepted an answer that doesn't tell you how to make it work:
(define-syntax special-if
(syntax-rules ()
((_ pre act alt)
(cond (pre act)
(else alt)))))
That defines a macro, which is expanded at compile time. Every time the compiler sees something that matches this pattern and begins with special-if, it gets replaced with the template shown. As a result, pre, act, and alt don't get evaluated until your special-if form gets turned into a cond form.
Understanding how macros work is difficult using Scheme, because Scheme does its damnedest to hide what's really going on. If you were using Common Lisp, the macro would be a simple function that takes snippets of uncompiled code (in the form of lists, symbols, strings, and numbers) as arguments, and returns uncompiled code as its value. In Common Lisp, special-if would just return a list:
(defmacro special-if (pre act alt)
(list 'cond (list pre act)
(list t alt)))
Scheme macros work the same way, except the lists, symbols, etc. are wrapped in "syntax objects" that also contain lexical information, and instead of using list
operators such as car and cdr, Scheme and Racket provide a pattern-matching and template engine that delves into the syntax objects and handles the extra data (but doesn't allow you to handle any of it directly).