First, I apologize for the beginner question. I am an experienced developer, but new to Scheme. I have created a contract requiring a positive integer, but when I provide a real number, the contract is not violated:
(define/contract (listofOne n)
(-> (and integer? positive?) (listof integer?))
(cond
((= n 0) '())
(else (cons 1 (listofOne (- n 1))))))
(listofOne 12.5)
I expected the contract to be violated, but instead I got an infinite loop and a buffer overflow. Why did the contract remain unviolated? The first query in my predicate was integer?
, so I don't see how the contract could have returned true with an input of 12.5
.
EDIT: Just to clarify, I am not looking for a way to make the contract violate. I already know that I can use and/c, and (thanks to @soegaard) that I can reverse positive?
and integer?
to get it to violate. What I'm looking for at this point is to understand what is going on here.
Thanks in advance for the help!
UPDATE
I totally missed that you used and
and not and/c
in your example.
Try this:
#lang racket
(define/contract (listofOne n)
(-> (and/c integer? positive?) (listof integer?))
(cond
((= n 0) '())
(else (cons 1 (listofOne (- n 1))))))
(listofOne 12.5)
Result:
listofOne: contract violation
expected: integer?
given: 12.5
in: an and/c case of
the 1st argument of
(->
(and/c integer? positive?)
(listof integer?))
contract from: (function listofOne)
blaming: anonymous-module
(assuming the contract is correct)
at: unsaved-editor:2.18
SECOND UPDATE
Here is an explanation of and
.
The form
(and c1 c2)
means:
1. Evaluate `c1` giving a value `v`
2. If the value `v1` is false,
then the result of the `and`-expression is false.
(note that `c2` is not evaluated)
3. If the value `v1` is non-false,
then evaluate the expression `c2` giving a value `v2`.
4. The result of the and-expressions is v2.
Note: If c1 evaluates to true, then (and c1 c2)
gives the same result as c2
.
This means in particular that if c1
is a contract (which is a non-false value)
then (and c1 c2)
gives the same result as c2
.
In your example (and integer? positive?)
gives the same result as positive?
.
Note also that, this implies that (-> (and integer? positive?) (listof integer?))
works the same as (-> positive? (listof integer?))
.
In code:
(and c1 c2)
is the same as
(let ([v1 c1])
(if v1
(let ([v2 c2])
v2)
#f))
Since you want a contract that uses both c1
and c2
we need a different approach. Let's examine how we can combine two predicates to a simple predicate.
(and/p p1 p2)
Should be short for
(lambda (x)
(and (p1 x) (p2 x)))
Here and
is used on the values returned by the predicates - not on the predicates themselves.
The construct and/c
works similar to and/p
but the representation of contracts is more involved than predicates. The principle is the same though.
is short for
(let ([t c1])
(if t
t
c2))