What are test cases in scheme and how do I use them? - scheme

I'm a complete beginner at scheme, and want to know what test cases are, or even do.
For example, if I wanted to write a test case for the negative root quadratic function I already coded and tested, how would I do it?
(define (quadnegative a b c)
(* (/ (+ (sqrt (-(square b) (* 4 a c))) b) 2 a) -1))
;Value: quadnegative
(quadnegative 1 3 -4)
;Value: -4
Thank you in advance.

Start by taking a look at the documentation of your interpreter for the specific details, for instance in Racket here is the testing framework available out of the box.
In essence, a test case will compare the actual value of an expression with the expected value - if they match, then the test succeeds. Here's a basic example of how this works in Racket (assuming that you've selected an appropriate language such as "Beginning Student"):
(define (add-one x)
(+ 2 x)) ; an error!
(check-expect (* 21 2) 42) ; test will succeed
(check-expect (add-one 1) 2) ; test will fail
The above will produce an output like this:
Ran 2 tests.
1 of the 2 tests failed.
No signature violations.
Check failures:
Actual value 3 differs from 2, the expected value.
at line 5, column 0
For your tests, try to imagine test values of interest. Write some tests for inputs that return real values:
(check-expect (quadnegative 1 3 -4) -4)
And then, test for inputs that return imaginary values ... and so on. Try to be thorough in your tests, covering as many cases as possible, specially the unusual or "weird" cases that might result in "strange" output values.

Related

Functional programming side effects clarification

I'm currently trying to gain an understanding about side effects in general with regard to functional programming, racket to be exact. It's my understanding that it relates to changing the state of some variable, like a global one.
Here's some code that I've written;
; Define a variable with the value of 5
(define x 5)
; Define a function to add 1 to x
(define addX
(+ 1 x))
; Test out values
x
addX
x
Which outputs 5 6 5.
Shouldn't the last value be 6? Or is the fundamental principle that I'm missing, the fact that the value is stateless when using functional programming?
The way your code is written, you can think of x as a constant – ie, addX does not mutate the x binding.
It's like the same as (pseudocode)
constant X = 5
constant addX = X + 1
print(X) ; 5
print(addX) ; 6
print(X) ; 5
Functional programming requires the immutable data structures. If you approach scheme/racket with notions from other (imperative style) languages, you'll struggle and the code you produce will be very bad.
(+ 1 x) is an expression. The result of this expression, in the case where we have already (define x 5), is 6. That value just... percolates up to whatever tried to evaluate it. Whether we ask DrRacket to evaluate it, or we assign it to something else, like (define addX (+ 1 x)), what is changing is the expression is becoming the value.
So, if you want to assign a value to an identifier that is already introduced, you need to tell the interpreter to do this assignment. That form is set!, as in,
(define addX #f)
addX ; => #f
(set! addX (+ 1 x))
addX ; => 6

case and quotation in scheme & racket

I was a bit surprised by this racket code printing nay when I expected yeah:
(define five 5)
(case 5
[(five) "yeah"]
[else "nay"])
Looking at the racket documentation for case makes it clearer:
The selected clause is the first one with a datum whose quoted form is equal? to the result of val-expr.
So it's about quotation. I'm pretty sure that I did not yet fully grasp what quotation in lisps can buy me. I understand it in the viewpoint of macros and AST transformation. However I'm confused why is it helpful in the case of case for instance..?
I'm also curious, with this specification of case, can I use it to achieve what I wanted to (compare the actual values, not the quoted value), or should I use another construct for that? (cond, while strictly more powerful, is more verbose for simple cases, since you must repeat the predicate at each condition).
The problem is that case introduces implicit quote forms, which cause your example to work for 'five (whose value is 'five), instead of five (whose value is 5).
I almost never use case because of exactly this problem. Instead I use racket's match form with the == pattern:
(define five 5)
(define (f x)
(match x
[(== five) "yeah"]
[_ "nay"]))
(f 5) ; "yeah"
(f 6) ; "nay"
This produces "yeah" on only the value 5, just like you expected. If you wanted it to return "yeah" when it's equal to either five or six, you can use an or pattern:
(define five 5)
(define six 6)
(define (f x)
(match x
[(or (== five) (== six)) "yeah"]
[_ "nay"]))
(f 5) ; "yeah"
(f 6) ; "yeah"
(f 7) ; "nay"
And if you really want to match against quoted datums, you can do that by writing an explicit quote form.
(define (f x)
(match x
[(or 'five 'six) "yeah"]
[_ "nay"]))
(f 5) ; "nay"
(f 6) ; "nay"
(f 7) ; "nay"
(f 'five) ; "yeah"
(f 'six) ; "yeah"
These quote forms are implicit and invisible when you use case, lurking there waiting to cause confusion.
The Racket documentation gives this grammar:
(case val-expr case-clause ...)
where
case-clause = [(datum ...) then-body ...+]
| [else then-body ...+]
Let's compare to your example:
(define five 5)
(case 5 ; (case val-expr
[(five) "yeah"] ; [(datum) then-body1]
[else "nay"]) ; [else then-body2])
We see that (five) is interpreted as (datum). This means that five is
a piece of data (here a symbol), not an expression (later to be evaluated).
Your example of case is evaluated like this:
First the expression 5 is evaluated. The result is the value 5.
Now we look at a clause at a time. The first clause is [(five) "yeah"].
Is the value 5 equal (in the sense of equal?) to one of the datums in (five)? No, so we look at the next clause: [else "nay"]. It is an else-clause so the expression "nay" is evaluated and the result is the value "nay".
The result of the case-expression is thus the value "nay".
Note 1: The left-hand sides of case-clauses are datums (think: they are implicitly quoted).
Note 2: The result of val-expr is compared to the clause datums using equal?. (This is in contrast to Scheme, which uses eqv?.
UPDATE
Why include case? Let's see how one can write the example using cond:
(define five 5)
(let ([val five])
(cond
[(member val '(five)) "yeah"]
[(member val '(six seven)) "yeah"] ; added
[else "nay"])
This shows that one could do without case and just use cond.
However - which version is easier to read?
For a case expression it is easy to see which datums the value is compared to.
Here one must look closely to find the datums. Also in the example we know beforehand that we are trying to find the value among a few list of datums. In general we need to examine a cond-expression more closely to see that's what's happening.
In short: having a case-expression increases readability of your code.
For the historically interested: https://groups.csail.mit.edu/mac/ftpdir/scheme-mail/HTML/rrrs-1986/msg00080.html disussed whether to use eqv? or equal? for case.
UPDATE 2
I'll attempt to given an answer to:
I'm still not clear on the quotation vs working simply on the values though.
I'm wondering specifically why doing the quotation, why working on datum instead
of working on values. Didn't get that bit yet.
Both approaches make sense.
Let's for the sake of argument look at the case where case uses expressions rather than datums in the left hand side of a clause. Also following the Scheme tradition, let's assume eqv? is used for the comparison. Let's call such a
case-expression for ecase (short for expression-case).
The grammar becomes:
(ecase val-expr ecase-clause ...)
where
ecase-clause = [(expr ...) then-body ...+]
| [else then-body ...+]
Your example now becomes:
(define five 5)
(ecase five
[('five) "yeah"]
[else "nay")
This doesn't look too bad and the result is what we are used to.
However consider this example:
(ecase '(3 4)
[('five (list 3 4) "yeah"]
[else "nay")
The result of this would be "nay". The two lists resulting from evaluating the expressions '(3 4) and (list 3 4) are not equal in the sense of eqv?.
This shows that if one chooses to use eqv? for comparisions, having expressions available on the left hand side won't be helpful. The only values that work with eqv? atomic values - and therefore one could just as well use implicit quotations and restrict the left hand side to datums.
Now if equal? was used it would make much more sense to use expressions on the left hand side. The original Racket version of case was the same as the one in Scheme (i.e. it used eq?) later on it was changed to used equal?. If case was designed from scratch, I think, expressions would be allowed rather than datums.
The only remaining issue: Why did the authors of Scheme choose eqv? over equal? for comparisons? My intuition is that the reason were performance (which back in the day was more important than now). The linked to post from the rrrs-authors mailing list gives two options. If you dig a little further you might be able to find responses.
I can't find a reference right now, but case statements use literal, unevaluated data in their different clauses because it is both a frequent use-case and more easily subject to efficient compilation.
You could probably write your own version of Clojure's condp macro or a custom conditional operator to handle your use case.

Scheme - syntax with if statements

Can anyone explain why this isn't working? I am following the documentation and I cannot understand why I get an error:
(define (functionName n)
(if (n < 10) ;;if condition
1 ;; then condition
3)) ;; else condition
I get the error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: 5
arguments...:
#<procedure:<>
10
You can see this in two ways. Your code is correct and you just called it wrong (bad type for n) or your code was accidentally written in infix notation. I'll illustrate both:
Passed wrong argument
n can be any data type and it can even be a procedure and if it is there is nothing wrong with your code:
(define (compare-15 predicate-procedure argument)
(predicate-procedure 15 argument))
(define (compare-2 predicate-procedure argument)
(predicate-procedure 2 argument))
(functionName compare-15) ; ==> 3
(functionName compare-2) ; ==> 1
What happens is that your procedure is calling the supplied procedure with a procedure for comparing < and an argument.
Accidental infix
Algol programmers are used to prefix fun( expr ) and infix x cmp y while in LISP dialects all those have one common form and that is prefix all the way: (fun expr) and (cmd x y).
(define (function-name n)
(if (< n 10) ;; predicate expression
1 ;; consequent expression
3)) ;; alternative expression
(function-name 15) ; ==> 3
(function-name 2) ; ==> 1
Since Scheme can have functions as argument, meaning every argument can be put in the first position, it might be exactly what you wanted and Scheme doesn't know until it gets a number to be called as a procedure that something is wrong.
The error message is quite clear when you know that every procedure call is called application. It expected to call a procedure but behind the variable n there was a number. "expected a procedure that can be applied to arguments. given: 5" probably makes more sense now?
Try this:
(define (functionName n)
(if (< n 10)
1
3))
Remember: Scheme uses prefix notation, meaning that all operators must go before the operands. In other words, this is wrong: (n < 10), and this is correct: (< n 10).
The function should be the first thing in the if (scheme uses prefix notation, not infix).
(define (functionName n)
(if (< n 10) ;;if condition
1 ;; then condition
3)) ;; else condition
Then
(functionName 2)
Outputs
1
when I run it in Chicken Scheme.

Algorithm evaluating user-defined functions

Hello I have some homework that consists of extending a lisp interpreter. We are to build three primitives with pre-evaluated arguments ( for exemple <= ), and three primitives who do their own evaluation ( for example if ).
I went beyond the call of duty and created the only fun function in the bounds of this exercice : (defun) [it's the common lisp keyword for defining a user-function].
I would like to know if my algorithm for managing a user-defined function call is worthwhile.
In pseudo code, here it goes :
get list of parameters # (x y z)
get list of arguments # (1 2 3)
get body of function # (+ x (* y z))
for each parameter, arg # x
body = replace(parameter, argument, body) # (+ 1 (* y z))
# (+ 1 (* 2 z))
# (+ 1 (* 2 3))
eval(body) # 7
Are there better ways to accomplish this?
Thanks.
EDIT: replace() is a function recursing on sub-lists of body.
I never found better, no one proposed better, the question generated no interest whatever, and I'm on a rampage to close my opened questions, so here is the answer :
my algorithm was good enough.

Please Help Me Understand Scheme: No Arguments?

First time stackoverflow user but occasional lurker, hope you guys can help me out.
So the first part of my assignment is to drop all 'leading zeros' in a list.
ex: (0 0 0 0 0 1 0 1 0 1) -> (1 0 1 0 1)
To do this, I thought to use an IF statement to check whether the first element was a 0 or not, and to recursively call the rest of the list until the there were no more leading zeros. As I have basically no idea how to program in Scheme, through searching the internet, I came up with what you see below. However when I run it, DrRacket tells me there are no arguments- I assume this either a syntactical error.. or more likely, I have no idea what I'm doing. So, if you could help me out, I'd really appreciate it!
>(define zz
> (lambda (n)
> (if (= (car (n)) 0)
> (zz (cdr (n)))
> ((n)))))
>
>(remove '(0 0 0 0 1 0 1 0))
The error I get in DrRacket is:
"procedure application: expected procedure, given: (0 0 0 0 1 0 1 0) (no arguments)"
Again, thanks a lot! (P.S. Sorry if the formatting is a little odd...)
EDIT
Okay, changing up some stuff, I now get a "expects type as 1st argument, given: (0 0 0 0 0 1 0 1 0); other arguments were: 0" error flagged at my if statement.
>(define zz
> (lambda n
> (if (= (car n) 0) <----- here
> (zz(cdr n))
> (n))))
EDIT 2
>(define zz
> (lambda (n)
> (if (= (car n) 0)
> (zz (cdr n))
> n)))
It works, thank you very much!
(num) is not correct - you're trying to call 42 or whatever as a command. (Also, your if syntax is off; you may want to do read more code to get a better feel for the syntax).
This should compile:
(define remove
(lambda (num)
(if (= (car num) 0)
(remove (cdr num))
num)))
Parenthesis in Lisp are for calling functions, unless used in quotes.
Okay, the OP asked about a general rundown of the syntax for Scheme.
a - A symbol, which is looked up by the evaluator and substituted for its value. Some symbols (such as 42) evaluate to themselves.
'a - This "quotes" the symbol and transforms it into (quote a). quote prevents its argument from being evaluated - instead, the value a is returned. Not the string "a", not the result of looking up a, a itself. This also works for lists ('(1 2 3))
(if <expr> <true-value> <false-value>) - This evaluates <expr>, and sees if its value is truthy or not, and executes the corresponding value.
(cond (<expr> <true-value>)
...
(else <false-value>)) - This runs though its arguments, and evaluates the car of it to see if it is true. If it is, the value of evaluating the cdr is returned. Otherwise, it skips to the next value.
(define <name> <expr>) - Sets the value of evaluating the second argument to the name of the first argument.
(lambda <arg-list> <body>) - Creates a procedure which is the result of binding the arguments passed in to the names present in the second argument and evaluating the third argument.
(<func> <arg1> <arg2> ... <argn>) - If the evaluator finds out that none of the above patterns match, then it calls the car of the list as a function, with the arguments in the cdr.

Resources