how to use the if statement in scheme programming? - scheme

I just started learning the scheme language and below is a question that I stuck a little bit(Is there anything wrong with my code cuz the error message is kinda weird)
Prompt: Define a procedure over-or-under which takes in a number x and a number y and returns the following:
-1 if x is less than y
0 if x is equal to y
1 if x is greater than y
What I've tried so far is :
(define (over-or-under x y)
(if (< x y)
-1)
(if (= x y)
0)
(if (> x y)
1)
)
The error message is :
scm> (load-all ".")
Traceback (most recent call last):
0 (adder 8)
Error: str is not callable: your-code-here
scm> (over-or-under 5 5)
# Error: expected
# 0
# but got

The syntax of if is:
(if condition expression1 expression2)
and its value is the value of expression1 when the condition is true, otherwise it is the value of expression2.
In your function instead you use:
(if condition expression1)
and this is not allowed. Note, moreover that the three ifs one after the other are executed sequentially and only the value of the last one is actually used, as the value returned by the function call.
A way of solving this problem is using a “cascade” of if:
(define (over-or-under x y)
(if (< x y)
-1
(if (= x y)
0
1)))
Note that the proper alignment make clear the order of execution of the different expressions. If (< x y) is true than the value -1 is the result of the if, but, since it is the last expression of the function, it is also the value of the function call. If this is not true, we execute the “inner” if, checking if x is equal to y, and so on. Note also that in the third case is not necessary to check if x is greater than y, since it is surely true, given that x is not less than y, neither equal to y.
Finally, note that the “cascade” of x is so common that in scheme exists a more syntactically convient way of expressing it with the specific cond expression:
(cond (condition1 expression1)
(condition2 expression2)
...
(else expressionN))
so you could rewrite the function is this way:
(define (over-or-under x y)
(cond ((< x y) -1)
((= x y) 0)
(else 1)))

Related

Scheme Function (DrRacket)

So, i'm trying to write the following function in scheme, and to be able to run it on DrRacket. The problem is as follows,
make5 - takes two integers, and returns a 5-digit integer constructed of the rightmost 3 digits of the first input, and the leftmost 2 digits of the second input. For example, (make5 561432 254) would return 43225.
Negative signs on either input number should be ignored - that is, (make5 561432 -254) would also return 43225.
If the first number has less than three digits or the last three digits start with zeros, and/or the second number has less two digits, your
function should return -2. Note: you may want to define some auxiliary functions.
So far this is the function I've been able to write.
(define (make5 x y)
(cond ((< (length x) 3) -2)
((< (length y) 2) -2)
(((modulo (abs(x)) 1000) 0) -2)
(((modulo (abs(y)) 1000) 0) -2)
(else (append (list-tail x 3) (cons (first(y)second(y)))))))
I'm getting the error...
application: not a procedure;
expected a procedure that can be applied to arguments
Any advice would be appreciated. I'm new to scheme and still trying to grasp everything.
Don't wrap your arguments in parentheses - (abs(x)) means "call the procedure x and pass the result to abs.
(cons (first(y)second(y)) means "cons these four things: the value of first; the result of calling the procedure y; the value of second; and the result of calling the procedure y".
(You've called procedures correctly in some places. Stick to the same pattern.)
You're also missing a comparison in a couple of conditions; (= (modulo (abs x) 1000) 0).
The inputs are not lists, they're integers, so you can't apply length, first, or any such things to them.
The result should be an integer, not a list, so you can't construct it using append and cons, you should only use arithmetic.
These facts about integers should get you started:
A number has fewer than five digits if it is smaller than 10000.
The last four digits of a non-negative number n is (modulo n 10000).
If x is 12 and y is 34, x * 100 + y is 1234.
To get the three leftmost digit in an integer, you can divide by 10 repeatedly until you have a number less than 1000.
Also note that the second number only has one condition on its digits while the first has two, and that the note about defining auxiliary functions was not left there as a challenge for you to do without them.
For instance, if you had the auxiliary functions
(left-digits n x), which produces the leftmost n digits of x, and
(right-digits n x), which produces the rightmost n digits of x
you could write (it's also probably not a coincidence that the description uses the words "if" and "or"):
(define (make5 x y)
(if (or ( ... ))
-2
(+ (* 100 (right-digits 3 x)) (left-digits 2 y))))
Since you want to ignore the sign of the numbers, it's convenient to take care of abs once at the start, using let:
(define (make5 signed-x signed-y)
(let ((x (abs signed-x))
(y (abs signed-y)))
(if (or ( ... ))
-2
(+ (* 100 (right-digits 3 x)) (left-digits 2 y)))))
"All" that's left now is filling in the conditions and writing the two digit-extracting functions.

Scheme procedure with 2 arguments

Learned to code C, long ago; wanted to try something new and different with Scheme. I am trying to make a procedure that accepts two arguments and returns the greater of the two, e.g.
(define (larger x y)
(if (> x y)
x
(y)))
(larger 1 2)
or,
(define larger
(lambda (x y)
(if (> x y)
x (y))))
(larger 1 2)
I believe both of these are equivalent i.e. if x > y, return x; else, return y.
When I try either of these, I get errors e.g. 2 is not a function or error: cannot call: 2
I've spent a few hours reading over SICP and TSPL, but nothing is jumping out (perhaps I need to use a "list" and reference the two elements via car and cdr?)
Any help appreciated. If I am mis-posting, missed a previous answer to the same question, or am otherwise inappropriate, my apologies.
The reason is that, differently from C and many other languages, in Scheme and all Lisp languages parentheses are an important part of the syntax.
For instance they are used for function call: (f a b c) means apply (call) function f to arguments a, b, and c, while (f) means apply (call) function f (without arguments).
So in your code (y) means apply the number 2 (the current value of y), but 2 is not a function, but a number (as in the error message).
Simply change the code to:
(define (larger x y)
(if (> x y)
x
y))
(larger 1 2)

Scheme "Not a function" error

I am learning Scheme and I keep getting this error: "Error: 20 is not a function" from the following code:
(define myFunction (lambda (x y)
(* x y)))
(define (higherOrder func x y)
(
func x y))
(display ((higherOrder myFunction 4 5)))
I am trying to pass a function as one of the arguments. It goes through with the math since it says "20" in the error message and (5 * 4 = 20) but then it thinks it is a function. What is the problem? I cannot figure it out. I am running this code on https://repl.it/languages/Scheme.
You have one too many pairs of parens, the expression (higherOrder myFunction 4 5) evaluates to the integer 20, then the repl tries to evaluate (20), which it can't because 20 isn't a function. When Scheme evaluates a list (where a list is anything in parens that isn't quoted) the first entry in the list is assumed to be a function.
Change the last line to
(display (higherOrder myFunction 4 5))

how do i open a racket REPL with the current scope?

Let's say I have a program like this:
(define (foo x)
(local
((define y (- x 1)))
(* x y)))
(foo 3)
I want to be able to open a REPL between lines 3 and 4, such that I can explore (and possibly modify) the values of x and y by executing arbitrary statements.
To do this in Ruby, I would take the equivalent program:
def foo(x)
lambda {
y = x - 1
x * y
}.call
end
puts (foo 3)
And modify it by adding a call to pry to give me a nicely-scoped repl where I want it:
require 'pry'
def foo(x)
lambda {
y = x - 1
binding.pry
x * y
}.call
end
puts (foo 3)
To do it in js, I would run this program under Firebug and just put a breakpoint on line 4:
foo = function(x) {
return (function(){
var y = x - 1;
return x * y;
})();
};
console.log(foo(3));
And then I could explore stuff in the evaluation window.
Is there anything I can do to get this in Racket? The closest I've found is DrScheme's debugger, but that just presents all the values of the current scope, it doesn't let you explore them in a REPL as far as I can see.
This isn't answering your original question, it's in response to your comment about making your own. I thought that was a really interesting idea so I explored it. What I was able to figure out:
Let's say you want this to work:
(define top-x 10)
(define (f)
(for ([i 10])
(displayln i)
(when (= i 5)
(pry)))) ; <= drop into a REPL here, resume after exiting REPL
A first attempt at pry:
(define (pry)
(let loop ()
(display "PRY> ")
(define x (read))
(unless (or (eof-object? x) (equal? x '(unquote exit)))
(pretty-print (eval x))
(loop))))
This seems to work:
> (f)
0
1
2
PRY> (+ 10 10)
20
PRY> ,exit
3
4
>
But although it lets you access Racket functions like +, you can't access even your top-level variables like top-x:
> (f)
0
1
2
PRY> top-x
; top-x: undefined;
; cannot reference undefined identifier
You can get the top-level stuff by giving eval access to the current namespace, as explained here. So pry needs a namespace argument:
(define (pry ns)
(let loop ()
(display "PRY> ")
(define x (read))
(unless (or (eof-object? x) (equal? x '(unquote exit)))
(pretty-print (eval x ns)) ; <---
(loop))))
And to get that argument you need this incantation to your debugee file:
(define-namespace-anchor a) ; <---
(define ns (namespace-anchor->namespace a)) ; <---
(define top-x 10)
(define (f)
(for ([i 5])
(displayln i)
(when (= i 2)
(pry ns)))) ; <---
Now the REPL can see and change top-x:
> (f)
0
1
2
PRY> top-x
10
PRY> (set! top-x 20)
#<void>
PRY> top-x
20
PRY> ,exit
3
4
>
Cool! But it can't change the local variable, i:
> (f)
0
1
2
PRY> i
; i: undefined;
; cannot reference an identifier before its definition
Shoot. The reason why is explained here.
You might imagine that even though eval cannot see the local bindings in broken-eval-formula, there must actually be a data structure mapping x to 2 and y to 3, and you would like a way to get that data structure. In fact, no such data structure exists; the compiler is free to replace every use of x with 2 at compile time, so that the local binding of x does not exist in any concrete sense at run-time. Even when variables cannot be eliminated by constant-folding, normally the names of the variables can be eliminated, and the data structures that hold local values do not resemble a mapping from names to values.
You might say, OK, but in that case...
How does DrRacket provide a debugger?
From what I was able to figure out, DrRacket does this by annotating the syntax before evaluating the program. From drracket/gui-debugger/annotator.rkt:
;; annotate-stx inserts annotations around each expression that introduces a
;; new scope: let, lambda, and function calls. These annotations reify the
;; call stack, and allows to list the current variable in scope, look up
;; their value, as well as change their value. The reified stack is accessed
;; via the CURRENT-CONTINUATION-MARKS using the key DEBUG-KEY
So I think that would be the jumping-off point if you wanted to tackle this.
In the DrRacked IDE you have a DEBUG Q >| button. You can step through your program or you can do as you said in other languages, press right mouse button at the expression you want to investigate and either choose continue to this point for once only or pause at this point for a breakpoint, then press GO > to run the program.
To inspect or change x, put you mouse pointer over it and use right mouse button. To change you choose (set! x ...) in the menu.
As for the in language repl, You could make your own (pry) to start a repl in there and in Common Lisp you could have just signaled an error to get to the nice debugger.

In Scheme, what's the point of "set!"?

What's the point of using the set! assignment operator in scheme? Why not just rebind a variable to a new value using define?
> (define x 100)
> (define (value-of-x) x) ;; value-of-x closes over "x"
> x
100
> (value-of-x)
100
> (set! x (+ x 1))
> x
101
> (value-of-x)
101
> (define x (+ x 1))
> x
102
> (value-of-x)
102
>
Though both define and set! will redefine a value when in the same scope, they do two different things when the scope is different. Here's an example:
(define x 3)
(define (foo)
(define x 4)
x)
(define (bar)
(set! x 4)
x)
(foo) ; returns 4
x ; still 3
(bar) ; returns 4
x ; is now 4
As you can see, when we create a new lexical scope (such as when we define a function), any names defined within that scope mask the names that appear in the enclosing scope. This means that when we defined x to 4 in foo, we really created a new value for x that shadowed the old value. In bar, since foo does not exist in that scope, set! looks to the enclosing scope to find, and change, the value of x.
Also, as other people have said, you're only supposed to define a name once in a scope. Some implementations will let you get away with multiple defines, and some won't. Also, you're only supposed to use set! on a variable that's already been defined. Again, how strictly this rule is enforced depends on the implementation.
It is not usually permitted to define a variable more than once. Most REPLs allow it for convenience when you're trying things out, but if you try to do that in a Scheme program it will give you an error.
For example, in mzscheme, the program
#lang scheme
(define x 1)
(define x 2)
gives the error
test.ss:3:8: module: duplicate definition for identifier at: x in: (define-values (x) 2)
In addition, define has a different meaning when used inside of other contexts. The program
#lang scheme
(define x 1)
x
(let ()
(define x 2)
x)
x
has the output
1
2
1
This is because defines inside of certain constructs are actually treated as letrecs.
When you use lexical bindings you do not define them:
(let ((x 1))
(set! x (+ x 1))
x)
When you use define you create a new variable with the new value, while the old variable still exists with the old value; it is just hidden by the new one. On the command line you don't see the difference to set!, but define won't be usable for e.g. a loop counter in an imperative program.

Resources