Why can't I define an "or-function" in scheme? - scheme

I have found this question about the special function "or" in scheme:
Joe Hacker states loudly that there is no reason or in Scheme needs to be special -- it can just be defined by the programmer, like this:
(define (or x y)
(if x
#t
y))
Is Joe right?
I can't figure out why it shouldn't be possible to do that.
Could some scheme-expert please explain if this works, and if no: why not?

It's because this version of or evaluates all of its arguments (since it's a function), while the standard Scheme or (which is not a function but special syntax) doesn't. Try running (or #t (exit)) at the Scheme REPL and then try the same with your or function.
The behavior of the standard or is sometimes called short-circuited: it evaluates only those arguments that it needs to. This is very common for the binary boolean operator (or and and) across programming languages. The fact that or looks like a function call is a feature of Scheme/Lisp syntax, but looks deceive.

Whether it works or not depends on what you want it to do. It certainly works in the sense that for two given boolean values it will return the expected resulted. However it will not be functionally equivalent to regular or because it does not short-circuit, i.e. given your definition (or #t (/ 0 0)) will cause an error because you're dividing 0 by 0 while using regular or it would just return #t and not try to evaluate (/ 0 0) at all.

Related

Get variable value with a string in scheme

How can we get variable value with a string in scheme language as we can achieve this in Common Lisp:
> (defvar s 3)
> S
> (symbol-value (intern "S"))
> 3
I am accessing a parameter of parent function from the closure.
EDIT: I have found this solution, but I can't use eval because it evaluates at top level. Searching for alternatives.
(eval (string->symbol "s"))
EDIT 2: I have found that Common lisp code also try to find symbol in global space. So this question is basically for both Lisps(Common Lisp, Scheme).
Don't do that!
Variables are for when you know the variable at compile time. In that case it is never a string. You can still reason about strings in compile time but your code also needs to have a relation with the name for it to be interesting. When you use eval or other forms that evaluate structure and compile/run data in runtime you are probably not doing it right (but not always. I've in my 20 year career used eval intentionally in production code twice)
If you want to store values you use a data structure. An assoc would mimic a dynamic environment. You can also use a hash with a level indicator if the size is harmless.
You can't do what you want to do and in fact it is a confused thing to want to do.
Here's why what you are trying to do is confused. Consider how a Lisp system for which it was possible to do what you wanted would work. In particular consider something like this:
(define (foo a name)
(let ([b 10])
(display (get-value name))
(* a b)))
Where get-value is meant to be how you get the binding of whatever something is.
So, if I call (foo 10 "b") it should print 10 and return 100.
But wait: b is a compile-time constant in this code. Any compiler worth its salt is going to immediately turn this into
(define (foo a name)
(display (get-value name))
(* a 10))
And now there is no binding of b.
So there are two options here: what you want to work works and it is impossible to ever write a reasonable compiler for Scheme, or what you want to work doesn't work, and it is.

define if with cond doesn't work

I try to implement a "special-if" that suppose to behave like regular "if" with cond. Here's the code:
(define (special-if pre act alt)
(cond (pre act)
(else alt)))
To test if this works, I wrote a factorial function with this "special-if":
(define (factorial n)
(special-if (= n 1)
1
(* n (factorial (- n 1)))))
However, when I evaluate (factorial 3), it runs forever. Seems the predicate part (= n 1) was never evaluated. Can anyone tell me why this won't work? Thanks.
Your special if is doomed to fail, I'm afraid. Remember: if is an special form with different evaluation rules (and cond is a macro implemented using if), that's why an expression like this runs fine even though it has a division by zero:
(if true 'ok (/ 1 0))
=> 'ok
... whereas your special-if will raise an error, because it's using the normal evaluation rules that apply for procedures, meaning that all its arguments get evaluated before executing the procedure:
(special-if true 'ok (/ 1 0))
=> /: division by zero
Now you see why your code fails: at the bottom of the recursion when n is 1 both the consequent and the alternative will execute!
(special-if (= 1 1)
1 ; this expression is evaluated
(* 1 (factorial (- 1 1)))) ; and this expression too!
... And factorial will happily continue to execute with values 0, -1, -2 and so on, leading to an infinite loop. Bottom line: you have to use an existing special form (or define a new macro) for implementing conditional behavior, a user-defined standard procedure simply won't work here.
You've heard why your special-if doesn't work, but you accepted an answer that doesn't tell you how to make it work:
(define-syntax special-if
(syntax-rules ()
((_ pre act alt)
(cond (pre act)
(else alt)))))
That defines a macro, which is expanded at compile time. Every time the compiler sees something that matches this pattern and begins with special-if, it gets replaced with the template shown. As a result, pre, act, and alt don't get evaluated until your special-if form gets turned into a cond form.
Understanding how macros work is difficult using Scheme, because Scheme does its damnedest to hide what's really going on. If you were using Common Lisp, the macro would be a simple function that takes snippets of uncompiled code (in the form of lists, symbols, strings, and numbers) as arguments, and returns uncompiled code as its value. In Common Lisp, special-if would just return a list:
(defmacro special-if (pre act alt)
(list 'cond (list pre act)
(list t alt)))
Scheme macros work the same way, except the lists, symbols, etc. are wrapped in "syntax objects" that also contain lexical information, and instead of using list
operators such as car and cdr, Scheme and Racket provide a pattern-matching and template engine that delves into the syntax objects and handles the extra data (but doesn't allow you to handle any of it directly).

What is the semantic difference between defining a name with and without parentheses?

(Though this is indeed simple question, I find sometimes it is common mistakes that I made when writing Scheme program as a beginner.)
I encountered some confusion about the define special form. A situation is like below:
(define num1
2)
(define (num2)
2)
I find it occurs quite often that I call num2 without the parentheses and program fails. I usually end up spending hours to find the cause.
By reading the r5rs, I realized that definition without parenthesis, e.g. num1, is a variable; while definition with parenthesis, e.g. num2, is a function without formal parameters.
However, I am still blurred about the difference between a "variable" and "function".
From a emacs lisp background, I can only relate above difference to similar idea as in emacs lisp:
In Emacs Lisp, a symbol can have a value attached to it just as it can
have a function definition attached to it.
[here]
Question: Is this a correct way of understanding the difference between enclosed and non-enclosed definitions in scheme?
There is no difference between a value and a function in Scheme. A function is just a value that can be used in a particular way - it can be called (as opposed to other kinds of value, such as numbers, which cannot be called, but can be e.g. added, which a function cannot).
The parentheses are just a syntactic shortcut - they're a faster, more readable (to experts) way of writing out the definition of the name as a variable containing a function:
(define (num)
2)
;is exactly the same as
(define num
(lambda () 2) )
The second of these should make it more visually obvious that the value being assigned to num is not a number.
If you wanted the function to take arguments, they would either go within the parentheses (after num, e.g. (num x y) in the first form, or within lambda's parentheses (e.g. (lambda (x y)... in the second.
Most tutorials for the total beginner actually don't introduce the first form for several exercises, in order to drive home the point that it isn't separate and doesn't really provide any true functionality on its own. It's just a shorthand to reduce the amount of repetition in your program's text.
In Scheme, all functions are values; variables hold any one value.
In Scheme, unlike Common Lisp and Emacs Lisp, there are no different namespaces for functions and other values. So the statement you quoted is not true for Scheme. In Scheme a symbol is associated with at most one value and that value may or may not be a function.
As to the difference between a non-function value and a nullary function returning that value: In your example the only difference is that, as you know, num2 must be applied to get the numeric value and num1 does not have to be and in fact can't be applied.
In general the difference between (define foo bar) and (define (foo) bar) is that the former evaluated bar right now and foo then refers to the value that bar has been evaluated to, whereas in the latter case bar is evaluated each time that (foo) is used. So if the expression foo is costly to calculate, that cost is paid when (and each time) you call the function, not at the definition. And, perhaps more importantly, if the expression has side effects (like, for example, printing something) those effects happen each time the function is called. Side effects are the primary reason you'd define a function without parameters.
Even though #sepp2k has answered the question, I will make it more clearer with example:
1 ]=> (define foo1 (display 23))
23
;Value: foo1
1 ]=> foo1
;Unspecified return value
Notice in the first one, foo1 is evaluated on the spot (hence it prints) and evaluated value is assigned to name foo1. It doesn't evaluate again and again
1 ]=> (define (foo2) (display 23))
;Value: foo2
1 ]=> foo2
;Value 11: #[compound-procedure 11 foo2]
1 ]=> (foo2)
23
;Unspecified return value
Just foo2 will return another procedure (which is (display 23)). Doing (foo2) actually evaluates it. And each time on being called, it re-evaluates again
1 ]=> (foo1)
;The object #!unspecific is not applicable.
foo1 is a name that refers a value. So Applying foo1 doesn't make sense as in this case that value is not a procedure.
So I hope things are clearer. In short, in your former case it is a name that refers to value returned by evaluating expression. In latter case, each time it is evaluated.

How to capture the return value of `string-search-forward` in Scheme?

I want to write a procedure (function) that checks if a string contains another string. I read the documentation of string library from http://sicp.ai.mit.edu/Fall-2004/manuals/scheme-7.5.5/doc/scheme_7.html
According from to them,
Pattern must be a string. Searches
string for the rightmost occurrence of
the substring pattern. If successful,
the index to the right of the last
character of the matched substring is
returned; otherwise, #f is returned.
This seemed odd to me, cause the return value is either integer or boolean, so what should I compare my return value with?
I tried
(define (case-one str)
(if (= #f (string-search-forward "me" str))
#t
#f))
DrScheme don't like it,
expand: unbound identifier in module in: string-search-forward
Thanks,
string-search-forward is not a standardized Scheme procedure; it is an extension peculiar to the MIT-Scheme implementation (that's why your link goes to the "MIT Scheme Reference Manual.") To see only those procedures that are guaranteed, look at the R5RS document.
In Scheme, #f is the only value that means "false," anything else when used in a conditional expression will mean "true." There is therefore no point in "comparing" it to anything. In cases like string-search-forward that returns mixed types, you usually capture the return value in a variable to test it, then use it if it's non-false:
(let ((result (string-search-forward "me" str)))
(if result
(munge result) ; Execute when S-S-F is successful (result is the index.)
(error "hurf") ; Execute when S-S-F fails (result has the value #f.)
))
A more advanced tactic is to use cond with a => clause which is in a sense a shorthand for the above:
(cond ((string-search-forward "me" str) => munge)
(else (error "hurf")))
Such a form (<test> => <expression>) means that if <test> is a true value, then <expression> is evaluated, which has to be a one-argument procedure; this procedure is called with the value of <test> as an argument.
Scheme has a very small standard library, which is both a blessing (you can make small scheme implementations to embed in an application or device, you can learn the language quickly) and a curse (it's missing a lot of useful functions). string-search-forward is a non-standard function of MIT Scheme, it's not present in DrScheme.
Many library additions are available in the form of SRFIs. An SRFI is a community-adopted extension to the base language — think of it as an optional part of a Scheme implementation. DrScheme (or at least its successor Racket) implements many SRFIs.
DrScheme has a number of string functions as part of SRFI 13. Amongst the string searching functions, there is string-contains, which is similar except that it takes its arguments in the opposite order.
(require srfi/13)
(define (case-one str)
(integer? (string-contains str "me")))
You'll notice that the two implementations used a different argument order (indicating that they were developed independently), yet use the same return value. This illustrates that it's quite natural in Scheme to have a function return different types depending on what it's conveying. In particular, it's fairly common to have a function return a useful piece of information if it can do its job, or #f if it can't do its job. That way, the function naturally combines doing its job (here, returning the index of the substring) with checking whether the job is doable (here, testing whether the substring occurs).
Error message seems a little odd (I don't have drscheme installed unfortunately so can't investigate too much).
Are you sure str is a string?
Additionally = is for integer comparisons only, you can use false? instead.
As for the return value of string-search-forward having mixed types, scheme has the mindset that if any useful value can be returned it should be returned, so this means different return types are common for functions.
Try using srfi-13's string-index: http://docs.racket-lang.org/srfi-std/srfi-13.html#Searching The documentation you are looking at isn't specifically for PLT. and probably corresponds to some other version of Scheme.

In Scheme, can if be expressed as a combination of boolean operators?

It is easy to express and, or, and not in terms of if (with an assist from a local binding for or). I'd like to know if the reverse is true. My naïve first attempt:
(if test conseq altern) => (or (and test conseq) altern)
However, if test is non-#f and conseq is #f, the translation evaluates to altern, which is incorrect.
Is there a translation that evaluates to the correct value while maintaining the short-circuit nature of if?
Sounds like you have a good explanation why if is doing a little more than and and or. But if you could cheat and add a lambda to delay the actual result:
(define-syntax-rule (if c t e) ((or (and c (lambda () t)) (lambda () e))))
Try (or (and test conseq) (and (not test) altern)) as the general pattern. By negating test in the second and, it ensures that the outer disjunction will be either conseq ∨ #f if test is true, or #f ∨ altern if test is false.
This is the same as Eli Barzilay's answer, except instead of wrapping it in a lambda, I wrap it in a 1-element list
(if test conseq altern) => (car (or (and test (list conseq)) (list altern)))
By the way, Python prior to 2.5 had this exact problem. There was no nice way to write a conditional expression (i.e. test ? conseq : altern in C, which is what if in Scheme is) in Python. The simplest attempt was
test and conseq or altern
which worked in most cases, but failed when conseq is considered false in Python (i.e. False, 0, empty list, empty string, etc.). Which is the exact problem you discovered above. The fix was to wrap it in a list (non-empty lists are always true) and extract it again:
(test and [conseq] or [altern])[0]
which looks ugly. Which is why they added the syntax conseq if test else altern in Python 2.5.

Resources