Scheme - eq? compare between 2 strings? - scheme

I have a problem in my program.
I have a condition that compare between 2 string:
(if (eq? (exp1) (exp2)))
When exp1 give me a string, and exp2 give me a string. To be sure, when I change the "eq?" to "=", it give me the next problem:
=: expects type <number> as 2nd
argument, given: ie; other arguments
were: ie.
When I'm running the program, the function doesnt enter to the first expression in the "if" function, and enter to the second one (meaning the condition is false).
What can I do?
Thank you.

According to the Equivalence predicates section of R6RS, you should be using equal?, not eq?, which instead tests whether its two arguments are exactly the same object (not two objects with the same value).
(eq? "a" "a") ; unspecified
(equal? "abc" "abc") ; #t
As knivil notes in a comment, the Strings section also mentions string=?, specifically for string comparisons, which probably avoids doing a type check.

I wrote a little helper function for this problem.
; test if eq?
(define ==
(lambda (x y)
(if (and (string? x) (string? y))
(string=? x y)
(if (or (string? x) (string? y))
(= 1 0) ;return false
(equal? x y)))))
(define a "aString")
(define l '("aString" "aOtherString"))
(== (car l) a) ; true
(== 1 1) ; true
(== 1 0) ; false
(== "a" 1) ; false diff. type
(== "a" "b") ; false
(== "a" "a") ; true
(== '("a" "b") '("a" "b"))

Related

Will a procedure be considered as a predicate, <p> , when the special form cond is missing the key word else?

I accidentally forgot to put the else in the following cond expression, and something strange occurred.
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
(+ 1 2 1001)
))
> (abs 1)
1001
>
the result of (abs 1) is not the result of (+ 1 2 1001),which is 1004, but the last element of the arguments of the expression (+ 1 2 1001).
the cond form is
(cond (<p1>,<e1>)
(<p2>,<e2>)
(<p3>,<e3>)
...
(<pn>,<en>))
there is no predicate in the expression (+ 1 2 1001), so I wonder if the procedure + has been considered as predicate, and if it always evaluates as true, selecting the last element to return. Is that how it works???
Sequencing: begin form in Racket allows you to sequence multiple expressions. It evaluates each expression from left to right and the final result is the last expression.
Syntax: The syntax for cond shows that multiple expressions can be sequenced in the rhs of a clause without a begin. Such a thing is called an implicit begin.
Semantics: According to the documentation, cond evaluates the rhs of a clause if the lhs is anything but #f. Therefore + in the position of the test-expression evaluates the rhs of the clause.
Style: By convention, using square brackets in a few key places makes Racket code even more readable. The clause of a cond is one of these places.
The following snippet is equivalent to your snippet:
#lang racket
(define (abs x)
(cond [(< x 0) x]
[(= x 0) 0]
[+ (begin 1
2
1001)]))
(abs 1)
; => 1001
cond works like this:
(cond (test-expr then-body)
(test-expr2 then-body2)
(else then-body3))
The test-exprs are tested one by one, and the first test-expr that returns a non-false value causes its corresponding then-body to be executed. The last value in the executed then-body is the value of the whole cond.
In Scheme, anything not #f is considered true. Therefore, + is considered true. In your cond, + acts like an else because it is always true. In fact, your code could be written like this without any change in behavior:
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
(else 1 2 1001)))
In your original code, the first test-expr that returns a non-false value is +. Since 1001 is the last value of the executed then-body, 1001 is the value of the whole cond. That's why you got 1001.
cond is a way to do if-elseif*-else in lisp and getting a flatter structure than with nesting of if. Since cond is derived form you could write your conditional in terms of if. Your procedure would become:
(define (abs x)
(if (< x 0)
x
(if (= x 0)
0
(if +
(begin
1
2
1001)))))
The last if checks if + is truthy. Every expression not evaluating to #f is truthy so all procedures are truty. It will then evaluate every part 1, 2, then 1001 and since that is the tail expression that is the result of the evaluation. You can have as many consequences in each cond term, but all before the tail is just for effect.
You could add one extra pair of parentheses and it would work as you expected:
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
((+ 1 2 1001))))
Here it has no addictional consequences and the truthy result of the predicate is the result for (abs 1). One would want the code to be as clear as possible so using else here is a much better option:
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
(else (+ 1 2 1001))))
This helps with another problem as well. While a number is always thruthy if you do the predicate trick with something that may be #f the result is undefined in the spec. Thus:
(cond ((other-proc x)))
; ==> ??
If the call to other-proc is truthy the result is that, if it is #f you get the result chosen by the implementers. These are almost always truthy values with crazy visualizations like #<undefined> but can be anything like "BaNaNa" or even #f. Thus it is wise to have an else term so that you and not some other developer gets to choose the outcome :-)

Error in case construct with string comparison (scheme)

(define aaa ;;val:string
(lambda(x) ;;x:string
(case
((string=? (substring x 0 1) "+") (aaa(substring x 1)))
((string=? "a" "b")(string-append("-" (aaa(substring x 1)))))
((char=?(string-ref x 0)#\.) (-404))
(else
(if (= (findpoint x) -1)
"a"
"b"
)
)
)
)
)
Hello, I have a problem with DrRacket:
When I try to run this code, it gives me the error:
case: expected a symbol (without its quote) or a number as a choice, but found a string
referring to the line (5):
((string=? "a" "b")(string-append("-" (aaa(substring x 1)))))
This line was actually supposed to look like this,
((string=? (substring x 0 1) "+")(string-append("-" (aaa(substring x 1)))))
but I thought that using two strings "a" "b" would ease to spot the problem.
I don't understand why i get this error, since both "a" "b" are strings and not symbols or lists, and also I can't understand why I don't get this error on the previous line
CONTEXT:
the procedure is supposed check if the first character of a string is a +/-/., and then do thing through recursion using else (again, "a" "b" are examples)
It seems like you are mixing cond, the flat if-elseif-else, and case, which is similar to a switch statement.
How to use cond:
(cond ((equal? 1 2) 'consequent)
((odd? 1) 'consequent2) ; as many terms as you want. It stops at the first true
(else 'alternative)) ; or else it evaluates the alterntaive
; ==> consequent2
Vs how to use case
(case 'value4
((value1 value2) 'consequent)
((value3 value4) 'consequent2)
(else 'default))
; ==> consequent2
Now that case statement is just sugar. Your Scheme implementation will make it into something similar to this:
(cond ((and (eqv? 'value4 'value1) (eqv? 'value4 'value2)) 'consequent)
((and (eqv? 'value4 'value3) (eqv? 'value4 'value4)) 'consequent2)
(else 'default))
Thus notice the values to match in a case are treated as if they are quoted. Eg. you values can not be variables since they will only match their symbol.
If you want to use case I would have done this:
(define (first-letter-operator? str)
(case (string-ref str 0)
((#\+ #\- #\.) #t)
(else #f)))
(first-letter-operator? "+345634") ; ==> #t
(first-letter-operator? "hello") ; ==> #f

contract violation in my implementation of "map"

I'm beginning in Scheme (actually, Racket with DrRacket) and I want to practice by implementing a map function (apply a function to all elements of a list), but there's something wrong that I don't understand.
(I have, aside from my imperative background, a basic knowledge of haskell)
I want to translate the following piece of haskell (Just to show the algorithm) :
map f [] = []
map f x:xs = (f x) : (map f xs)
Here's my code :
(define (map f xs)
(if (= xs '()) '() ; if list is empty, return empty list
(cons (f (car xs)) (map f (cdr xs))))
)
To test it, I used this :
(define (testFunction x) (+ x 1))
(define testList '(1 2 3 4 5))
(map testFunction testList)
And I get the following error :
=: contract violation
expected: number ?
given : '(1 2 3 4 5)
argument position: 1st
other arguments...:
which highlights the predicate (= xs '())
Any tips ?
The = function is specifically for equality between numbers. It has special handling for numeric values by handling comparisons between exact and inexact numbers. In general, though, for non-numeric equality, you should use the equal? predicate:
> (equal? '() '())
#t
In this particular case, as mentioned by Raghav, you can also use empty? or null? to test for the empty list (the empty? predicate is just an alias for null?).
Wow - a few others already beat me to it, but I'll share my answer, anyways.
Your issue stems from your use of = to test list emptiness.
From the = in the docs:
Returns #t if all of the arguments are numerically equal, #f
otherwise.
In order to get your program working, I'd suggest using equal? to test the two lists for equality or, better yet, use empty? or null? to test if xs is an empty list. (I hope you don't take offense, but I've also massaged the code into what's (arguably) more idiomatic Scheme).
(define (mymap f xs)
(if (empty? xs)
xs
(cons
(f (car xs))
(mymap f (cdr xs)))))
(define (test-function x) (+ x 1))
(define test-list (list 1 2 3 4))
(mymap test-function test-list)
If you're using DrRacket, then for that condition, simply use (empty?):
(if (empty? xs)
xs ; because xs is empty
...)

How do I use and/or instead of if/cond?

I'm new to Scheme programming and I've gotten this task that I just can't find out how to work correctly. I'm supposed to define a procedure with one parameter (a number). If the number is positive I want 1 to be returned, -1 if the number is negative and 0 if it is 0, using only and/or. If and cond is not allowed. I only get #t or #f returned, but you see that's not what I want. Any help or pointers is appreciated
You can solve your problem if you look at the following equivalence, valid when every expj has a value different from #f:
(cond (test1 exp1) (or (and test1 exp1)
(test2 exp2) (and test2 exp2)
... ≡ ...
(testn expn) (and testn expn)
(else expn+1)) expn+1)
Since the function that gets the sign of a number can simply be written in this way:
(define (sign x)
(cond ((> x 0) +1)
((< x 0) -1)
(else 0)))
after applying the above equivalence, since every result is an integer, different from #f, this function becomes equal to the solution proposed also in another answer:
(define (sign x)
(or (and (> x 0) +1)
(and (< x 0) -1)
0))
So, which is the reason of the above equivalence? It depends on the fact that and evaluates its arguments in turn; as soon as one of them is #f, it stops by returning #f, otherwise returns its last argument (and this explains the single branches (and testj expj)); while or evaluates its arguments in turn; as soon as one of them is not #f, it stops by returning it, otherwise returns its last argument (and this explains the chain (or (and ...) (and ...) ... expn+1)).
(define test
(lambda (n)
(or (and (< n 0) -1)
(and (= n 0) 0)
1)))
Part of the trick is understanding that and, if everything evaluates to true, will return the last item it evaluated, while or will return the first thing that successfully evaluates to true. The other part is realizing that everything except for #f is considered "true."
The transformation of and is seen in the report but to not include the actual macros it's basically this:
; only one argument
(and a) ; ===>
a
; one of more
(and a b ...) ; ==>
(if a
(and b ...)
#f)
All arguments must be evaluate to a positive value and the last value is the result, else #f. It short circuits so when something is #f the rest of the expressions are never evaluated.
For or is like this:
(or a) ; ==>
a
(or a b ...) ; ==>
(let ((a-value a))
(if a-value
a-value
(or b ...)))
The first argument that does not evaluate to #f gets returned. If all values are #f the last #f will be the result.
Thus if you want:
(if a b c) ; ==>
(let ((tmpa a))
(or (and atmpa b)
(and (not atmpa) c)) ; not part only important if b can be #f
I use let to prevent evaluating the same expression several times. eg. if you had one that printed something like (begin (display "hello") #f) or it's an expensive calculation then it's necessary or else you can just substitute the variable with the expression. eg. the last would become:
(or (and a b)
(and (not a) c))
That transformed back with no temporary variables become:
(if (if a b #f)
(if a b #f)
(if (not a) c #f))
If b is #f value, then the result is #f because of the last if. Thus everytime a is true b is the result. Everytime it's false, c is the answer. Thus
(if a b c)
So imagine you want to return the first true value in a list.
(define (first-true lst)
(and (not (null? lst))
(car lst)
(first-true (cdr lst))))

Function for detecting quotes in Scheme code

I am trying to write a function that can check whether or not some input is a quotation for a syntax checker.
I have the following code:
(define is-quote-expression?
(lambda (v)
(equal? (car v) 'quote)
(is-quotation? (cdr v)))))
(define is-quotation?
(lambda (v)
(or (number? v)
(boolean? v)
(char? v)
(string? v)
(symbol? v)
(null? v)
(and (pair? v)
(is-quotation? (car v))
(is-quotation? (cdr v)))))
When I try to evaluate, I get the following:
(is-quote-expression? '1)
#f
(is-quote-expression? (cons 'quote 1))
#t
I think my TA told me that the Scheme environment replaced all "'" with "'quote", however, this does not seem to be the case. We are running Petite Chez Scheme.
What am I not seeing?
Thanks in advance.
There are a couple of problems with your code, for starters the (lambda (pair? v) part in is-quote-expression? is almost certainly a mistake (you're defining a lambda with two parameters called pair? and v).
Also, I believe you intended to call is-quotation? from is-quote-expression? only if v isn't a pair, so it doesn't make sense to ask again if (pair? v) in is-quotation?. And who said that a pair is a quotation only if both its car and cdr are quotations?
Here, I believe this is what you intended:
(define is-quote-expression?
(lambda (v)
(if (pair? v)
(equal? (car v) 'quote)
(is-quotation? v))))
(define is-quotation?
(lambda (v)
(or (number? v)
(boolean? v)
(char? v)
(string? v)
(symbol? v)
(null? v))))
I agree with Óscar's post, though, is-quote-expression? accepts a list rather than a pair and returns whether it was a quotation.
(define is-quote-expression?
(lambda (v)
(and (proper-list-of-given-length? v 2)
(equal? (car v) 'quote)
(is-quotation? (cadr v)))))
Also, your original question shows some confusion as to what quote actually does. This is what really should happen:
> (is-quote-expression? '1)
#f
> (is-quote-expression? (cons 'quote 1))
#f
> (is-quote-expression? (quote 42))
#f
> (is-quote-expression? (quote (quote 42)))
#t
Note how the built-in quote procedure simply returns what it is passed. In the case of (quote 42) it simply returns 42. But (quote (quote 42)) returns (quote 42), which is what you wish to pass to is-quote-expression?.
The behavior of quote is specified in R6RS, appendix A.3. For '1, the relevant rule is 6sqv:
(store (sf1 ...) S1[ 'sqv1 ]) → (store (sf1 ...) S1[ sqv1 ])
Time to break this down.
The "S → T" notation defines one step in evaluating a term, where "S" evaluates to "T".
Since store and the sf1 non-terminals appear the same on both the left and right sides, you don't need to understand them to understand how '1 evaluates. If you need something, think of store as "storage environment" and the sfn as pairs of names and values; (store ((x 1) (y 2)) S) means the identifier x is associated with the value 1 and y with 2 when evaluating the term S.
If you're not familiar with the S[e] notation, it refers to a term with one "hole" (an term with a [] in it) filled with e. There are two related syntax elements: terms with holes (S[]) and terms with a hole filled by a value (S[e]). Holes are a little (but only a little) like unnamed variables. One important difference is that a term is allowed only one hole. Holes are perhaps best explained by example. All of the following are S[]:
(+ [] 1 2)
(list [] 'a "foo")
(cond ((= x 0) [])
((> x 0) 1)
(else -1))
Note that a hole can only appear where a sub-term is syntactically valid; [] 2) is not a term-with-hole. S[0] would be a term with 0 substituted into the hole:
(+ 0 1 2)
(list 0 'a "foo")
(cond ((= x 0) 0)
((> x 0) 1)
(else -1))
When a value is given for a hole, the term S[] is also called a "context". This comes from one of the primary uses for terms-with-holes: to match any term containing the given value. S[e] is any term that contains e as a valid sub-term, so S[] is the context that e appears in. In short, S1['sqv1] is a stand-in for any term that contains a quote.
(+ 'foo 1 2)
(list 'bar 'a "foo")
(cond ((= x 0) 'baz)
((> x 0) 1)
(else -1))
Note the second term provides two different contexts for quote-terms: (list [] 'a "foo"), (list 'bar [] "foo"). This suggests that you shouldn't think of holes too much as just being unnamed variables.
If you're wonder why context terms and holes are used, they're an alternative to recursive definitions. Without contexts, → would have to be defined recursively over the structure of terms (Scheme's grammar defines the structure). Substitution in lambda calculus is an example of structural recursion, as are any tree-processing functions you might define in Scheme (though Scheme syntax is quite different than the syntax used to define → and lambda calculus substitution).
(define (tree-depth tree)
(if (pair? tree)
(max (tree-depth (car tree))
(tree-depth (cdr tree)))
1
) )
Next, let's examine the meaning of sqv, which is short for "self-quoting values". This is a non-terminal from the Scheme grammar, given in appendix A.2.
sqv ::= n | #t | #f
n ::= [numbers]
sqv is simply a number or boolean.
All together, the 6sqv evaluation rule means that a quoted number or boolean evaluates to the number or boolean; the quote is simply discarded.
What this signifies for your homework is that you can't tell the difference between 1 and '1 with a normal function, since sub-terms are evaluated before the function is called. You'll need a macro.
Why go through all this just to say that "'1 evaluates to 1"? Firstly, answering "why" takes more than answering "what". Also, it will hopefully help you go beyond the question, learning a little bit how to read Scheme's formal semantics, give you a taste of computational theory concepts and lead to many more questions.

Resources