Scheme - logical operator procedures - scheme

I know Scheme and other Lisp dialects include logical operators such as 'and' and 'or', but, since I am currently learning Scheme, I am trying to program my own logical operators. So far my attempts at 'or' have been successful (at least so far as my testing has shown me). My logical or operator is the following:
(define (logical-or a b)
(if a true b))
I am trying to program a logical operator for 'and' that also returns a boolean, but I keep getting stuck. I have tried any number of combinations, but I will just list the following one, which doesn't return a boolean:
(define (logical-and a b)
(if a b false))
Any hints or help welcome.

As Uselpa's answer and the leppie's comments mentioned, the operators and and or don't return #t but the value that was not #f that decided the outcome of the form. Thus
(and 'these 'are 'all 'true 'values) ; ==> values
(or 'these 'are 'all 'true 'values) ; ==> these
The logical operators and and or are short circuiting so they are not procedures. Imagine this procedure:
(define (first-true-value lst)
(and (pair? lst)
(or (car lst)
(first-true-value (cdr lst)))))
(first-true-value '()) ; ==> #f
(first-true-value '(#f #f)) ; ==> #f
(first-true-value '(#f #f hello)) ; ==> hello
If you replace and and or with your versions the procedure will never stop evaluating the recursion.
We know we can rewrite and with if. (and) is #t, (and a) is a and (and a b ...) is (if a (and b ...) #f). We could do this with th easiest Scheme macros, syntax-rules:
(define-syntax logical-and
(syntax-rules ()
((logical-and) #t)
((logical-and a) a)
((logical-and a b ...)
(if a (logical-and b ...) #f))))
We can also do or the same way. (or) is #f and (or a b ..) is (if a a (or b ...)):
(define-syntax logical-or
(syntax-rules ()
((logical-or) #f)
((logical-or a b ...) ; NB: zero elements match "b ..."
(if a a (logical-or b ...)))))
There is a problem with this one since it uses a twice.. Try (logical-or (display "hello")). It will evaluate (display "hello") and thus display the text twice. To fix this we need to wrap the value in a let:
(define-syntax logical-or
(syntax-rules ()
((logical-or) #f)
((logical-or a b ...)
(let ((tmp a))
(if tmp
tmp
(logical-or b ...))))))
If you try the same it will only display "hello" once. Lets try writing my initial procedure with the new macros:
(define (first-true-value lst)
(logical-and (pair? lst)
(logical-or (car lst)
(first-true-value (cdr lst)))))
;; and we test them:
(first-true-value '()) ; ==> #f
(first-true-value '(#f #f)) ; ==> #f
(first-true-value '(#f #f hello)) ; ==> hello

Your logical-or does not always return booleans either:
> (logical-or #f 2)
2
As #leppie says, anything not false (#f) is true in Scheme; try experimenting a little with the build-in or function:
> (or 1 2)
1
> (or #f 2)
2
> (or #t 2)
#t
> (or 1 #f)
1
> (or #f #t)
#t
so the definition in Scheme would be:
(define (my-or a b)
(if a a b))
Likewise, for and:
> (and 1 #t)
#t
> (and 1 #f)
#f
> (and 1 2)
2
> (and #f 2)
#f
> (and #t 2)
2
so the definition is
(define (my-and a b)
(if a b a))
If you want to only return booleans, then you'd code
(define (logical-or a b)
(cond
(a #t)
(b #t)
(else #f)))
(define (logical-and a b)
(if a
(if b
#t
#f)
#f))
This works for 2 values, but since the build-in and and or operators allow any number of parameters (even 0) and only evaluate their parameters if necessary the real definitions are a little more complicated.

Related

What is Classifier and Transformer in MIT Scheme?

In the following scheme code, accumulate does right-fold. When I tried to run using mit scheme. I ran into following error:
Transformer may not be used as an expression: #[classifier-item 13]
Classifier may not be used as an expression: #[classifier-item 12]
I google searched but didn't find useful information. Is it related a macro?
; This function is copied from SICP chapter 2
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
; works as expected
(accumulate
(lambda (x y) (or x y)) ; replace or with and also works
#f
'(#t #f #t #f #f)
))
; does not work
; error: Classifier may not be used as an expression: #[classifier-item 12]
(accumulate
or
#f
'(#t #f #t #f #f)
))
; does not work
; error: Transformer may not be used as an expression: #[classifier-item 13]
(accumulate
and
#f
'(#t #f #t #f #f)
))
Macros can be passed around in some languages, but not in Scheme and Common Lisp. The reason is that macros should be able to be expanded ahead of time. eg.
(define (cmp a b)
(cond ((< a b) -1)
((> a b) 1)
(else 0)))
Now a compiling Scheme will expand each node recursively replacing it with the expansion until it is no change:
(define (cmp a b)
(if (< a b)
(begin -1)
(cond ((> a b) 1)
(else 0))))
(define (cmp a b)
(if (< a b)
-1
(cond ((> a b) 1)
(else 0))))
(define (cmp a b)
(if (< a b)
-1
(if (> a b)
(begin 1)
(cond (else 0)))))
(define (cmp a b)
(if (< a b)
-1
(if (> a b)
1
(cond (else 0)))))
; end result
(define (cmp a b)
(if (< a b)
-1
(if (> a b)
1
0)))
From this point of cond doesn't need to exist in the underlying language at all since you'll never ever use it, but how would this have to be implemented to work:
(define (test syntax a b)
(syntax a b))
(test or #f #t)
For this to work the underlying language needs to know what or is even after expansion since syntax would need to be bound to or and then the transformation can happen. But when the code runs the macro expansion has already happened and in most implementations you would see something indicating that or is an unbound variable. It seems like MIT Scheme has added error checking for top level syntax syntax that will fire an error if you don't override it. Eg. if you add this you will not see any problems whatsoever:
(define (or a b) (if a a b))
(define (and a b) (if a b #f))
Now after those lines any reference to and and or are not the syntax, but these procedures. There are no reserved words in Scheme so if you do something crazy, like defining define you just cannot use it for the rest f that scope:
(define define display) ; defiens define as a top level variable
(define define) ; prints the representation of the function display
(define test 10) ; fail since test is an undefined variable so it cannot be displayed.
I created a interpreted lisp with macros that actually could be passed, but it isn't very useful and the chances of optimization is greatly reduced.
Yes it's related to the macros / special forms like and and or.
You can make it work simply by wrapping them as lambdas, (accumulate (lambda (a b) (or a b)) ...) -- the results will be correct but of course there won't be any short-circuiting then. The op is a function and functions receive their arguments already evaluated.
Either hide the arguments behind lambdas ((lambda () ...)) and evaluate them manually as needed, or define specific versions each for each macro op, like
(define (accumulate-or initial sequence)
(if (null? sequence)
initial
(or (car sequence)
(accumulate-or initial (cdr sequence)))))
Here sequence will still be evaluated in full before the call to accumulate-or, but at least the accumulate-or won't be working through it even after the result is already known.
If sequence contains some results of heavy computations which you want to avoid in case they aren't needed, look into using "lazy sequences" for that.

Scheme Switch-Statement Syntax

What is the smartest way to create a switch statement in Scheme?
I want to check one value up against several others, if one results true the entire function should result true, otherwise false. I am not very good with the syntax in scheme.
In Scheme you have case:
(case (car '(c d))
((a e i o u) 'vowel)
((w y) 'semivowel)
(else 'consonant)) ; ==> consonant
As you see it compares against literal data. Thus you cannot compare the value with other variables. Then you need cond
An alternative to an explicit comparison agains each value, is to use member:
> (define (vowel? x) (member x '(a e i o u))
> (vowel? 'b)
#f
Base Case
Often if you want to return a boolean value a simple boolean expression will be enough. In the simple case several checks within an or will be enough:
(define (switch val)
(or (equal? val 'some-value)
(equal? val 'some-other-value)
(equal? val 'yet-another-value)))
Higher Order Function
Is we're doing this often it's a lot of work, so we can make a function called make-switch that takes a list of values and returns a function that serves as a switch statement for those values:
(define (make-switch list-of-vals)
(define (custom-switch val)
(define (inner vals)
(cond ((null? vals) #f)
((equal? val (first vals)) #t)
(else
(inner (rest vals)))))
(inner list-of-vals))
Then we can use make-switch like this:
> (define k (make-switch '(1 2 a "b")))
> (k 1)
#t
> (k 5)
#f
> (k "a")
#f
> (k "b")
#t
Faster Lookups
If we're mostly checking against a static set of values, then a hash-table is another alternative. This code in #lang racket shows the general approach, an R5RS Scheme could use SRFI-69:
#lang racket
(define (make-switch alist)
(define (list->hash alist)
(make-hash (map (lambda (x) (cons x x))
alist)))
(lambda (val)
(if (hash-ref (list->hash alist) val #f)
#t
#f)))
Note
There may be cases where you want to use eq? or some other test for equality, but I've left make-custom-make-switch as an exercise for further exploration.

Why does this scheme function run correctly then produce an "illegal function" error?

I'm attempting to write a scheme function that prints each entry of a list on a new line. This function and sample input works as expected, then gives an "illegal function" error and exits. I'm using tinyscheme from the debian repos.
(define print-list
(lambda (l)
(if (null? l)
(display "done\n")
(
(display (car l))
(newline)
(print-list (cdr l))
)
)
)
)
(print-list '(1 2 3 4 5) )
A parenthesis followed by an expression means function application.
(expr1 expr2 ...)
Means evaluate expr1, expr2, .... Then apply the result of expr1 to the result of expr2 ... . If the result of expr1 is not a function, then you'll see the "illegal function" error.
The fix is as leppie states to add a begin:
(define print-list
(lambda (l)
(if (null? l)
(display "done\n")
(begin
(display (car l))
(newline)
(print-list (cdr l))))))
(print-list '(1 2 3 4 5) )
Here
(begin expr1 expr2 ....)
means evalute expr1, expr2, ... in order. Finally return the value of the last expression.
Block Structure
In scheme, the branches of the if special form do not have an implicit block structure. As Soegaard suggests, begin may be used. Or you can use cond to create a block—in which case, expanding to more than two branches comes along for free.
(define (print-list a-list)
(cond ((null? a-list)(display "done\n"))
(else
(display (car a-list))
(newline)
(print-list (cdr a-list)))))
Problem with Return Type
Note that print-list is problematic because it returns...well something undefined. For example in MIT Scheme:
1 ]=> (print-list '(a b c))
a
b
c
done
;Unspecified return value
Or in Gauche Scheme:
gosh> (print-list '(a b c))
a
b
c
done
#<undef>
While in Racket's implementation of R5RS the return value is not printed.
> (print-list '(a b c))
a
b
c
done
Returning a Value
One common approach to signalling the end of a series of side effects is to return a value. null is one possibility. A symbol is another.
(define (print-list a-list)
(cond ((null? a-list) 'done) ; changed this line.
(else
(display (car a-list))
(newline)
(print-list (cdr a-list)))))
Calling it now will in a Scheme REPL removes the problematic return value:
gosh> (print-list '(a b c))
a
b
c
done

Using foldr with the or logical operator in Scheme

I'm attempting to run the following bit of code in Scheme using Dr.Racket
(foldr or #f '(#f #f #f #t))
Now, I expected this to work because
(foldr + 0 '(1 2 3))
Worked just fine, returning 6.
But when I try to run it with the logical or I get "or: bad syntax in: or"
What am I doing wrong? Also, is there an alternative method to calculate the or of a list without using folds, perhaps?
In the specific case of folding or, you should use ormap. You can pass in identity (or even values ) as the function to use with ormap.
> (ormap identity '(#f #f #f #f #t))
#t
> (ormap identity '(#f #f #f #f #f))
#f
In general, you can only fold functions, not macros, and or is a macro because it has short-circuiting behaviour.
My Scheme is fairly weak, but if I'm not mistaken, or is a macro, not a function, so you can't pass it around in higher-order calls. You can wrap it in a lambda, however, leading to the less-pleasant looking:
(foldr (lambda (a b) (or a b)) #f '(#f #f #f #t)) => #t
If you know the number of arguments in advance, it's worth noting that or takes zero or more arguments:
(or) => #f
(or #f) => #f
(or #t) => #t
(or #t #f) => #t
(or #f #f #f #f #f) => #f
Otherwise, you'll need a more experienced Schemer than me to provide the answer.

Using AND with the apply function in Scheme

Why doesn't the following work?
(apply and (list #t #t #f))
While the following works just fine.
(apply + (list 1 3 2))
This seems to be the case in both R5RS and R6RS?
and isn't a normal function because it will only evaluate as few arguments as it needs, to know whether the result is true or false. For example, if the first argument is false, then no matter what the other arguments are, the result has to be false so it won't evaluate the other arguments. If and were a normal function, all of its arguments would be evaluated first, so and was made a special keyword which is why it cannot be passed as a variable.
(define and-l (lambda x
(if (null? x)
#t
(if (car x) (apply and-l (cdr x)) #f))))
pleas notice that this is lambda variadic!
apply example (and-l #t #t #f)
or you can use it via apply procedure(as was asked)
for example (apply and-l (list #t #t #f))
both options are ok...
and is actually a macro, whose definition is outlined in R5RS chapter 4. The notation "library syntax" on that page really means it is implemented as a macro.
Section 7.3, Derived expression types gives a possible definition of the and macro:
(define-syntax and
(syntax-rules ()
((and) #t)
((and test) test)
((and test1 test2 ...)
(if test1 (and test2 ...) #f))))
Given this defintion, it is not possible to use and as a function argument to apply.
In the Scheme dialect MIT/GNU Scheme, you can use the function boolean/and instead of the special form and.
(apply boolean/and (list #t #t #f)) ;Value: #f
Also, for the record, I couldn’t find any equivalent function in Guile Scheme’s procedure index.
(Other answers have already explained why the special form and won’t work, and shown how to write your own replacement function if there isn’t already such a function in your dialect.)
If you REALLY wanted to have a function pointer to a function that does and, and you don't mind behavior different than the "real" and, then this would work:
(define and-l (lambda (a b) (and a b)))
Which you can apply like this:
(apply and-l (list #t #f))
The two caveats are:
All of the args get evaluated, in violation of the definition of and, which should have shortcutting behavior.
Only two arguments are allowed.
I've stumbled across the same problem and found an elegant solution in Racket.
Since the problem is that "and" is a macro and not a function in order to prevent the evaluation of all its arguments, I've read a little on "lazy racket" and found that "and" is a function in that language. So I came up with the following solution where I just import the lazy and as "lazy-and":
#lang racket
(require (only-in lazy [and lazy-and]))
(define (mm)
(map number? '(1 2 3)))
(printf "~a -> ~a\n" (mm) (apply lazy-and (mm)))
which yields
(#t #t #t) -> #t
try this:
(define list-and (lambda (args) (and (car args) (list-and (cdr args)))))
then you can use apply to list-and!
You could also use
(define (andApply lBoo)
(if (not (car lBoo)) #f
(if (= 1(length lBoo)) (car lBoo)
(andApply (cdr lBoo)))))
I also bump into this problem playing with PLT-Scheme 372, I have digged into the behavior of and-syntax, and figure out the follow code which works just as if one would intuitively expect (apply and lst) to return, but I haven't done exaustive test.
(define (list-and lst)
(cond
((null? lst) '())
((not (pair? lst)) (and lst))
((eq? (length lst) 1) (car lst))
(else
(and (car lst)
(list-and (cdr lst))))
)
)
Welcome to DrScheme, version 372 [3m].
Language: Textual (MzScheme, includes R5RS).
> (eq? (and '()) (list-and '()))
#t
> (eq? (and '#f) (list-and (list '#f)))
#t
> (eq? (and 'a) (list-and (list 'a)))
#t
> (eq? (and 'a 'b) (list-and (list 'a 'b)))
#t
> (eq? (and 'a 'b '()) (list-and (list 'a 'b '())))
#t
> (eq? (and 'a 'b '#t) (list-and (list 'a 'b '#t)))
#t
> (eq? (and 'a 'b '#f) (list-and (list 'a 'b '#f)))
#t
I've also figured out another mind-trapping workaround. I call it mind-trapping because at first I don't know how to turn it into a function... Here it is (only a demo of my intuitive idea):
Welcome to DrScheme, version 372 [3m].
Language: Textual (MzScheme, includes R5RS).
> (eval (cons 'and (list ''#f ''#f ''#t)))
#f
> (eval (cons 'and (list ''a ''b ''c)))
c
But later I asked a question and got the answer here: Is it possible to generate (quote (quote var)) or ''var dynamically? . With this answer one can easily turn the above idea into a function.
(define (my-quote lst)
(map (lambda (x) `'',x) lst))
(cons 'and (my-quote (list 'a 'b 'c)))
=> '(and ''a ''b ''c)

Resources