164 lines
6.9 KiB
Plaintext
164 lines
6.9 KiB
Plaintext
|
|
The _Programming Languages: Application and Interpretations_ languages
|
|
are companion to the textbook of the same name.
|
|
|
|
In the language dialog box, you will find the four _PLAI_ language:
|
|
|
|
PLAI - Beginning Student
|
|
PLAI - Intermediate Student with lambda
|
|
PLAI - Advanced Student
|
|
PLAI - Pretty Big
|
|
|
|
This language sequence follows the same progression as the book "How
|
|
to Design Programs" (htdp). If you are learning Scheme with the book
|
|
while taking the class, the PLAI languages will provide the same
|
|
support as the HtDP languages. Namely, at each language level the
|
|
error messages you receive are explained in term of the constructs you
|
|
know so far, and are tailored to address the common errors done at that
|
|
level.
|
|
|
|
--- Syntactic forms ---------------------------------------------------
|
|
|
|
> (define-type ID (VARIANT-ID (FIELD-ID CONTRACT-EXPR) ...) ...)
|
|
|
|
Defines the datatype ID and a function ID? that returns true for
|
|
instances of the datatype, and false for any other value. Here, the
|
|
name ID? means the given name ID, with an added question mark.
|
|
|
|
For each VARIANT-ID, a constructor VARIANT-ID is defined. The
|
|
constructor takes as many arguments as the variant's FIELD-IDs, and
|
|
it returns an instance of this datatype. Each argument to the
|
|
constructor is checked by applying the contract produced by the
|
|
variant's CONTRACT-EXPR.
|
|
|
|
In the PLAI Beginner language, a CONTRACT-EXPR should be the name of
|
|
a predicate, i.e., a procedure of one argument that returns a
|
|
boolean. In higher language levels, a CONTRACT-EXPR can produce
|
|
anything that is allowed as a contract by MzLib's "contract.ss"
|
|
library (which includes predicate procedures).
|
|
|
|
An instance constructed by the VARIANT-ID can be deconstructed using
|
|
`type-case'. Also, for each FIELD-ID of a VARIANT-ID, `define-type'
|
|
provides VARIANT-ID-FIELD-ID to access each field in an instance of
|
|
each variant, and a predicate VARIANT-ID? to recognize instances of
|
|
the variant.
|
|
|
|
In PLAI Intermediate and later, `define-type' produces additional
|
|
contract-related bindings, and it also supports a generalization of
|
|
ID. See "Datatypes and Contracts" below.
|
|
|
|
> (type-case DATATYPE-ID EXPR (VARIANT-ID (FIELD-ID ...) RESULT-EXPR ...) ...)
|
|
> (type-case DATATYPE-ID EXPR (VARIANT-ID (FIELD-ID ...) RESULT-EXPR ...) ...
|
|
(else ELSE-EXPR ...))
|
|
|
|
Branches on the datatype instance produced by EXPR, which must be an
|
|
instance of the specified DATATYPE-ID (previously defined with
|
|
`define-type'). Each clause pattern automatically extract the values
|
|
stored in the fields of the structure. It binds the extracted values
|
|
them to the names FIELD-IDs in the order that the fields were
|
|
declared in the corresponding definition in the `define-type'.
|
|
|
|
The `type-case' form complains if you do not handle all the variants
|
|
in a datatype. You can use the `else' keyword as the last clause of
|
|
a `type-case' to create a catch-all clause. In that case, variants
|
|
which are not handled by the other clauses will trigger the
|
|
evaluation of the ELSE-EXPR.
|
|
|
|
If it should not be possible to reach the `else' clause according to
|
|
the logic of your program, your ELSE-EXPR should be a call to
|
|
`error', which will raise an exception. For example:
|
|
|
|
(type-case shape a-circle
|
|
[circle (c r) (* pi (sqr r))]
|
|
[else (error "expected a circle!")])
|
|
|
|
--- Datatypes and Contracts ------------------------------------------------
|
|
|
|
> (define-type (ID PARAM-ID ...) (VARIANT-ID (FIELD-ID CONTRACT-EXPR) ...) ...)
|
|
|
|
This form of `define-type' is supported only in the PLAI
|
|
Intermediate langauge and higher.
|
|
|
|
Each PARAM-ID stands for a contract parameter, and can
|
|
appear as a free variable in the CONTRACT-EXPRs. When VARIANT-ID is
|
|
used directly, then `any/c' is substituted for each PARAM-ID to
|
|
obtain the relevant field contracts. Using ID by itself after
|
|
`define-type' is the same as (ID) with no PARAM-IDs.
|
|
|
|
VARIANT-ID-of is bound to a constructor generator for each
|
|
VARIANT-ID. Given a contract for each PARAM-ID, it produces a
|
|
constructor whose field contracts are the CONTRACT-EXPRs with
|
|
PARAM-IDs replaced by the given contracts.
|
|
|
|
ID-of/c is bound to a contract generator. Given a contract for each
|
|
PARAM-ID, it produces a contract that corresponds to the union of
|
|
the variant contracts PARAM-IDs replaced by the given contracts in
|
|
the CONTRACT-EXPRs.
|
|
|
|
Finally, VARIANT-ID-of/c is bound to a contract generator for each
|
|
VARIANT-ID. Given a contract for each PARAM-ID, it produces a
|
|
constructor whose field contracts are the CONTRACT-EXPRs with
|
|
PARAM-IDs replaced by the given contracts.
|
|
|
|
--- Testing support ---------------------------------------------------
|
|
|
|
> (test result expected-value)
|
|
|
|
Compares the result of a test expression to the expected value, and
|
|
return a list of three elements: the first element is the symbol
|
|
'good (if the test passed) or 'bad (if the test failed), the second
|
|
element is the result, and the third element is the expected value.
|
|
|
|
> (test/pred result predicate)
|
|
|
|
Applies the predicate to the result, and return a list of three
|
|
elements: the first element is the symbol 'good (if the predicate
|
|
returned true), or 'bad (if the predicate returned false), the
|
|
second element is the result, and the third element is the expected
|
|
values.
|
|
|
|
> (test/exn (lambda () expression) expected-error-message)
|
|
|
|
Evaluates the expression expecting an exception. This is useful to
|
|
verify that your program correctly detects error conditions. If the
|
|
expression does not raise an exception, TEST/PRED returns the list:
|
|
|
|
(list 'bad result expected-error-message)
|
|
|
|
If the evaluation of the expression did throw an exception, TEST/PRED
|
|
will pattern match the error message against the
|
|
expected-error-message, and return 'bad if the error was not the
|
|
expected error. EXPECTED-ERROR-MESSAGE should be a few words from
|
|
the expected error message. For example:
|
|
|
|
(text/exn (lambda () (/ 3 0)) "by zero")
|
|
|
|
evaluates to:
|
|
|
|
(list 'good #(struct:exn) "by zero")
|
|
|
|
> (print-tests false|true|'good|'bad|'stop)
|
|
|
|
PRINT-TESTS controls printing of test by TEST, TEST/PRED and TEST/EXN.
|
|
You can pass one of five values to PRINT-TESTS:
|
|
|
|
false Test result are not printed, they are simply returned. The
|
|
results of tests evaluated at the top-level will be
|
|
printed by DrScheme in the interaction panel, as usual.
|
|
(this is the default)
|
|
|
|
true all test results are printed
|
|
|
|
'good only successful test results are printed
|
|
|
|
'bad only failed test results are printed
|
|
|
|
'stop testing will stops at the first test that fails, by throwing
|
|
an exn:test exception.
|
|
|
|
> (test-inexact-epsilon number)
|
|
|
|
Sets the precision used by TEST to check the correctness of inexact
|
|
numbers. By default, floating-point results are considered correct
|
|
if they fall within 0.01 from their the expected value.
|