Why is this expression giving me a function body error? - scheme

(define (subtract-1 n)
(string-append "Number is: " (number->string n))
(cond
[(= n 0) "All done!"]
[else (subtract-1(- n 1))]))
I keep getting the error: define: expected only one expression for the function body, but found 1 extra part. I'm not understanding why I'm getting this.
NOTE TO SELF: When using DrRacket, Setting the language to BSL may make Racket commands error at compile time.

The language you're using (BSL) only allows a single expression inside the body of a procedure, if there's more than one expression, you need to pack them inside a begin.
Also notice that the string-append line is doing nothing, you should print it or accumulate it. Here's a possible solution with my recommendations in place:
(define (subtract-1 n)
(begin
(display (string-append "Number is: " (number->string n) "\n"))
(cond
[(= n 0) "All done!"]
[else (subtract-1 (- n 1))])))
Even better, use the printf procedure for simplicity's sake:
(define (subtract-1 n)
(begin
(printf "~a ~s~n" "Number is:" n)
(cond
[(= n 0) "All done!"]
[else (subtract-1 (- n 1))])))
Either way a sample execution looks like this:
(subtract-1 3)
=> Number is: 3
=> Number is: 2
=> Number is: 1
=> Number is: 0
=> "All done!"

Racket documentation (Sequencing) seems to suggest that you might need to use a begin expression for this to work, or it might be the missing space in (subtract-1(- n 1)) between the function name and the parameter.
Also, you probably want to output the result of
string-append as it's not really doing anything as it is. Example to cover off all these points:
(define (subtract-1 n)
(begin
(write (string-append "Number is: " (number->string n)))
(cond
[(= n 0) "All done!"]
[else (subtract-1 (- n 1))])))

Related

In Scheme, how can I display something multiply times?

`(display-n "*" 4)`
****
This code should give 4 stars. How can I display this?
Also, this code should fit in this:
Finally figured out the entire good code. Thanks for all the hints and feedback!
(define (display-n k n)
(if (> n 0)
(do ((x 0 (+ x 1)))
((= x n))
(display k))))
(define (parasol n)
(define (triangle i)
(if (< i n)
(begin
(display-n " "(- n i 1))
(display-n "*" (+ (* 2 i) 1))
(newline)
(triangle (+ i 1)))))
(define (stick i)
(if (< i 3)
(begin
(display-n " " (- n 1))
(display "*") (newline)
(stick (+ i 1)))))
(triangle 0)
(stick 0))
(parasol 5)
Phrased differently, your question is:
How can I repeat an operation `n` times?
The solution is to use a loop. In Scheme you can choose between a "named let" or a "do loop".
See detailed explanation here:
What does the "do" control construct do in Scheme?
(define (display-n n k)
(if (> k 0)
(do ((x 0 (+ x 1)))
((= x k))
(display n))))
Found it. I'll put this here if an unfortunate soul is looking for the same thing.
For this specific case, since you're only outputting a single character long string, you can just make a string of n copies of that character and print it instead of using an explicit loop:
(define (display-n k n)
(display (make-string n (string-ref k 0))))
(display-n "*" 4)
or if passing a character instead of a string:
(define (display-n k n)
(display (make-string n k)))
(display-n #\* 4)
While knowing how to repeat an arbitrary task a given number of times is generally useful and probably a big point of the exercise, being able to find simpler approachs for special cases is also a good skill to have.

User input to a list

I'm trying to take in user input and add it to a list but I have not been able to get it working. I'm still new to scheme and have been browsing around to try to figure it out but I haven't had any luck.
(display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(define (intlist number)
(define number(read-line))
(cond (number? number)
(cons lst (number))
(else
(display lst)
done')))
this is what I have so far. Any help or direction to where I can learn a bit more is appreciated.
Your solution is almost correct, but it doesn't work, because:
Variable lst doesn't exist and with this expression (number), you are calling some undefined function number.
done' is badly written 'done.
Function cons expects element as first argument and other element or list as second argument.
See these examples:
> (cons 1 2)
'(1 . 2)
> (cons 1 '())
'(1)
> (cons 1 (cons 2 (cons 3 '())))
'(1 2 3)
Last example is important here- your function will be recursive and it will return a cons cell in each step. If I will follow your solution, this can be enough:
(define (list-from-user)
(let ((number (read)))
(if (number? number)
(cons number (list-from-user))
'())))
(Note that I used read instead of read-line, because read-line returns string, and let instead of define.)
If you really want to wait for e, you must decide, what happens if user enters something that isn't number and isn't e- maybe just ignore it?
(define (list-from-user)
(let ((user-input (read)))
(cond ((number? user-input) (cons user-input (list-from-user)))
((eq? user-input 'e) '())
(else (list-from-user)))))
Then just add some wrapping function with output:
(define (my-fn)
(begin (display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(list-from-user)))
and call it
> (my-fn)
Note that my function returns list with numbers, instead of some useless 'done, so I can use that function in other functions.
(define (sum-of-list)
(let ((lst (my-fn)))
(format "Sum of given list is ~a." (apply + lst))))
> (sum-of-list)

Scheme prime number assignment

I have this Scheme assignment where I need to display whether the integers in the range of 2-100 are prime or not. I know that Scheme does not allow one to change the value of a variable, but given how I did this I was wondering if this is fixable.
(let loop ((i 2))
(begin (print "")
(let loop ((j i))
(begin ()
(if (and (= (mod i j) 0) (not (= i j)))
(print i " is NOT PRIME"))
(if (= j 2)
(print i " is PRIME")
(loop (- j 1)))))
(if (= i 100)
(print "done first")
(loop (+ i 1)))))
You need to forget about counting/for loops for the moment, look for recursive patterns and helpful abstractions.
For instance this snippet may be helpfull
(define (test n)
(if (prime? n)
(begin (display i) (display " is prime.") (newline))
(begin (display i) (display " is NOT prime.") (newline))))
Also (let loop ((var binding) ...) body) is not what you think it is. It's not a variation of the C for i=x... Loop is just a name here, you could just as easily call it hiccup or roses. The form is used where defining an internal recursive function and calling it with specific expressions would do just as well, but where the sub-function wouldn't benifit from highly descriptive function and free variable names.

How do I sort my string list with Recursion?

I'm trying to write code where it creates a string list increasing order with using only recursion and nothing else.
How should I go about doing this?
(define (create-list n st)
(cond [(zero? n) ""]
[else (string-append "X" (create-list (sub1 n) st))]))
(define (stair n)
(cond [(equal? n 0) empty]
[else (cons (create-list n "x") (stair (- n 1)))]))
;; (stair 4) --> (list "XXXX" "XXX" "XX" "X")
Desired output: (list "X" "XX" "XXX" "XXXX")
Replace
(cons (create-list n "x") (stair (- n 1)))
with
(append (stair (- n 1)) (list (create-list n "Q")))
(Note that create-list doesn't actually use the st argument.)
All Scheme lists are created from end to beginning. You want to create ("XXXX") first, then ("XXX" "XXXX") etc. Whenever you do (cons "X" (recursion ....)) then (recursion ...) needs to finish before the cons while the most efficient is by using an accumulator. Using append each step smell wrong since append is O(n) so if you do do that each step then you have O(n^2). With a couple of thousand elements you'll start noticing the difference.
You don't need create-list, which doesn't create a list but a string, since Scheme has make-string that does what you want:
(make-string 3 #\X) ; ==> "XXX"
So here is stair:
(define (stair n)
(define (xs n)
(make-string n #\X))
(let helper ((n n) (acc '()))
(if (zero? n)
acc
(helper (- n 1)
(cons (xs n) acc)))))
So in this case if you wanted it in the reverse order you would have used different name than n and gone upward until this and n were passed. Sometimes you don't have the luxury to choose, eg, if you were to copy a list, then often you can building the reverse, then reverse the result. Sometime you need to use memory and need the continuations, but this will restrict how deep your structures can be before the program stops working. In rackets case it doesn't stop until you have depleted the whole heap memory you have supplied it.

How Do For Loops Work In Scheme?

I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why
(define (bubblesort alist)
;; this is straightforward
(define (swap-pass alist)
(if (eq? (length alist) 1)
alist
(let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
(if (> fst scnd)
(cons scnd (swap-pass (cons fst rest)))
(cons fst (swap-pass (cons scnd rest)))))))
; this is mysterious--what does the 'for' in the next line do?
(let for ((times (length alist))
(val alist))
(if (> times 1)
(for (- times 1) (swap-pass val))
(swap-pass val))))
I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.
Any thoughts on what's going on here?
That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.
(let loop ((times 10))
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))
gets expanded to something like
(letrec ((loop (lambda (times)
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))))
(loop 10))
This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).
What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.
Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.

Resources