fun f x y = (x,y);Now imagine that we wanted to use partial application to create a new function
g
that takes a single argument y and returns the pair
(3,y):
val g = f 3;
g
to create the pair (3,7).
Explain the error message you get.e
to (fn y => e y)
.
For example, if we wanted to create our function g
, we could use
eta expansion:
val g = (fn y => (f 3) y);
fun f2 x = (fn y => (x,y)); val g2 = f2 3;Fortunately, we can use eta-expansion in this situation as well:
val g2 = (fn y => (f2 3) y);However, eta-expansion does not always preserve the semantics of the program.
fun f x y = x (x y)
fun f x y = (x y) y
fun absorb x = absorb
fun create x = (create x) x
'a == (int * 'a list)
, which violates the "occurs
check". What error message does SML print?call/cc
and dynamic-wind
can easily be
used to implement exceptions as a user-level library. Here is one
possible API:
(throw v)
: throw an exception, with argument
(exception value) v
.(try f h)
: evaluate (f)
, returning its
result if it returns normally. If f
or a callee throws
an exception that's not handled by some dynamically nested try, then
evaluate (h v)
, where v
is the exception
value. Return the result of (h v)
as the result of
(try f h)
. (h v)
may itself throw an
exception, which is propagated to the try block enclosing this
try.Here is a trivial example of code that uses this API:
(define (apply-and-divide f x y default) (try (lambda () ; body (if (= y 0) (throw 'divide-by-zero) (f (/ x y)))) (lambda (exn) ; handler (if (= exn 'divide-by-zero) default (throw exn))))) ; returns #f due to divide-by-zero (apply-and-divide (lambda (v) (* v 100)) 5 0 #f) ; exn 'random-error propagates to top-level. Should print a message ; (using built-in display) and return nothing. (apply-and-divide (lambda (v) (throw 'random-error)) 5 2 #f)
The above apply-and-divide
function is roughly
equivalent to the following ML code:
exception DivideByZero fun applyAndDivide f x y default = (if y = 0 then raise DivideByZero else f (x / y)) handle DivideByZero => default
Read the documentation for call/cc
and
dynamic-wind
in the R5RS, and then do the following:
try
.throw
.Hint: these are the pieces you will need for your solution:
try
will use dynamic-wind
to add and
remove a handler around executing its body.throw
will pass the exception to the most recent
handler.You will need dynamic-wind
in order to handle the case
where the user invokes a continuation from inside the body of
try
. For example, consider the following code:
(call/cc (lambda (cont) (try (lambda () (cont "foobar")) (lambda (v) ("baz")))))
After evaluating this expression at toplevel, the handler stack should be empty.
In the previous assignment, you encoded objects using recursive records of functions, using ML datatypes to "close the loop" of recursion; and you encoded classes/constructors using functions that generated these records. In Haskell, the natural way to do "object-oriented programming" is with type classes, which directly support OO-like idioms.
Point
type class with all the operations of
the Point
type from the previous assignment.Colored
type class with only the operation
getColor
, which returns a string.ColoredPoint
type class that extends both
Colored
and Point
, and write an instance
of this type class.Test your type classes by writing a magnitude
function
over Point
s, and convince yourself that you can pass any
Point
to this class. Next, write a distance
function that takes two Point
s of arbitrary (possibly
different) representation and determines the (Euclidean) distance
between them. Third, write a triangleArea
function that
takes three Point
s of arbitrary representation
and determines the area of the triangle defined by those points. You
do not have to turn these three functinos in.
Lastly, try to write a pairwiseDistances
function that
takes a list of Point
s of arbitrary representation, and
computes the distance between all pairs of Point
s in the
list.
pairwiseDistances
would
have to be. Here are some suggestions for how to think about this
answer (you do not necessarily have to answer these following
questions; they're just to help you think):
distance
,
triangleArea
, quadrilateralArea
,
pentagonArea
, etc.? What is it about lists (or, for
that matter, arrays) that defeats the type system?Turn in: