In this function:
(defn my-post
[a]
{:post (number? %)}
a)
The post-condition doesn't execute (or at least, doesn't cause an assertion error). I now know that it should have been:
(defn my-post
[a]
{:post [(number? %)]} ;; note the square brackets around the expression
a)
Which does, in fact, work correctly.
The problem is that this failed silently, and took me a while to figure out what was wrong. No syntax errors, runtime exceptions.
I would like to understand what Clojure does with this code, in order to understand why Clojure didn't complain. Macro expansions? Destructuring? Does the code just disappear if it doesn't see square braces?
http://clojure.org/special_forms documents that the condition-map for fn (thus also defn) should be of the form:
{:pre [pre-expr*]
:post [post-expr*]}
{:post (number? %)} will result in (number? %) being treated as a sequence of assertions, which means it's interpreted as two separate assertions: number? and %.
user> (macroexpand-1 '(fn [a] {:post (number? %)} a))
(fn*
([a]
(clojure.core/let [% a]
(clojure.core/assert number?)
(clojure.core/assert %)
%)))
(assert number?) always passes as long as number? is defined and has a true value, which being a core function, it probably does. (clojure.core/assert %) passes if % has a true value. It's bound to the value of your argument a via the let, so it passes if a has a true value. Try calling (my-post nil) with your first function definition and it'll fail the assertion.
user> (my-post nil)
; Evaluation aborted.
; Assert failed: %
; [Thrown class java.lang.AssertionError]
If you properly put your post-condition in a vector, it expands like this:
user> (macroexpand-1 '(fn [a] {:post [(number? %)]} a))
(fn*
([a]
(clojure.core/let [% a]
(clojure.core/assert (number? %))
%)))
Related
I am trying to define a function func->symbol that takes a function and returns its name as a symbol. For example:
(define (pythagoras a b)
(sqrt (+ (* a a) (* b b))))
;; #1
(func->symbol pythagoras) ; Returns: 'pythagoras
;; #2
(func->symbol (if #t pythagoras sqrt)) ; Returns: 'pythagoras
;; #3
(let ((f (if #t pythagoras sqrt)))
(func->symbol f)) ; Returns: 'pythagoras
;; #4
(let ((f (if #t pythagoras sqrt)))
(let ((g f))
(func->symbol g))) ; Returns: 'pythagoras
This is a follow-up question on How do I get a definition's name as a symbol? which only deals with case #1. For case #1, a simple macro def->symbol is sufficient:
(define-syntax def->symbol
(syntax-rules ()
((_ def) 'def)))
However, this macro definition does not pass cases #2, #3, #4. Is it possible to define func->symbol, or is Scheme not expressive enough for this?
In Racket, in many cases, you can get a function's name using object-name. But it is probably a bad idea to rely on this result for anything other than debugging.
Perhaps it's worth an answer which shows why this is not possible in any language with first-class functions.
I'll define what I mean by a language having first-class functions (there are varying definitions).
Functions can be passed as arguments to other functions, and returned as values from them.
Functions can be stored in variables and other data structures.
There are anonymous functions, or function literals.
Scheme clearly has first-class functions in this sense. Now consider this code:
(define a #f)
(define b #f)
(let ((f (lambda (x)
(+ x 1))))
(set! a f)
(set! b f))
Let's imagine there is a function-name function, which, given a function, returns its name. What should (function-name a) return?
Well, the answer is that there's simply no useful value it can return (in Racket, (object-name a) returns f, but that's clearly exposing implementation details which might be useful for debugging but would be very misleading as a return value for a function-name procedure.
This is why such a procedure can't exist in general in a language with first-class functions: the function which maps from names to values is many-to-one and thus has no inverse.
Here is an example of the sort of disgusting hack you could do to make this 'work' and also why it's horrible. The following is Racket-specific code:
(define-syntax define/naming
;; Define something in such a way that, if it's a procedure,
;; it gets the right name. This is a horrid hack.
(syntax-rules ()
[(_ (p arg ...) form ...)
(define (p arg ...) form ...)]
[(_ name val)
(define name (let ([p val])
(if (procedure? p)
(procedure-rename p 'name)
p)))]))
And now, given
(define/naming a
(let ([c 0])
(thunk
(begin0
c
(set! c (+ c 1))))))
(define/naming b a)
Then:
> (object-name a)
'a
> (object-name b)
'b
> (eqv? a b)
#f
> (a)
0
> (b)
1
> (a)
2
So a and b have the 'right' names, but because of that they are necessarily not the same object, which I think is semantically wrong: if I see (define a b) then I want (eqv? a b) to be true, I think. But a and b do capture the same lexical state, so that works, at least.
In the book Structure and Interpretation of Computer Programs
by H. Abelson and G. J. Sussman with J. Sussman,
the accumulation or fold-right is introduced in Section 2.2.3 as follows:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
I tried to use this to take the and of a list of Boolean variables, by writing:
(accumulate and
true
(list true true false))
However, this gave me the error and: bad syntax in DrRacket (with #lang sicp),
and I had to do this instead:
(accumulate (lambda (x y) (and x y))
true
(list true true false))
Why? I believe it has something to do with how and is a special form,
but I don't understand Scheme enough to say.
Perhaps I'm just missing some obvious mistake...
You answered your own question: and is a special form (not a normal procedure!) with special evaluation rules, and accumulate expects a normal procedure, so you need to wrap it inside a procedure.
To see why and is a special form, consider these examples that demonstrate that and requires special evaluation rules (unlike procedures), because it short-circuits whenever it finds a false value:
; division by zero never gets executed
(and #f (/ 1 0))
=> #f
; division by zero gets executed during procedure invocation
((lambda (x y) (and x y)) #f (/ 1 0))
=> /: division by zero
obviously, this code should fail :
(define or 5)
but I was wondering why does this code fail to run :
(define apply
(lambda (x y f)
(f x y)
)
)
(apply #f #t or)
(or #f #t), would work as expected.
I'm not defining any new variable with a saved name, only passing the function or as an argument.
and (apply 1 2 +) on the other hand works...
or is a special form. It isn't a function. So it can not be passed like that as an argument. Rather than (apply #f #t or), you must use:
(apply #f #t (lambda (a b) (or a b)))
(define or 5) does not fail. It shadows the or special form. Some implementations may not allow redefinition either within a module or of given symbols. So when asking about Scheme it is important to specific the implementation.
This is because special forms can only occur in the first position. Special forms are implemented as macro expansions. For example: (or a b) => (let ((v a)) (if v v b))
When you want to redefine special forms you need to use thunks, otherwise the arguments get evaluated, while the arguments of the special forms are evaluated in the order imposed inside the special form.
Instead, to get the same behavior as the semantics of the special forms you can force and delay the argument evaluation by using thunks. For example,
(define (or-sp-form a b) (if (a) 'ok (b)))
and call such a function like
(or-sp-form (lambda () false) (lambda () true))
Defining a special form like that, it can now be passed as argument to other functions like
(f or-sp-form)
and take care inside f to pass delayed arguments to or-sp-form.
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))))
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.