Professional Documents
Culture Documents
Ex 8 Solutions
Ex 8 Solutions
Ex 8 Solutions
Exercise 8.1. Please take part in the lecture evaluation. If you have not received
an email from the SCI, go to https://vlu.cs.uni-kl.de/teilnahme/ and enter your
*@*.uni-kl.de email address.
1
Exercise 8.2. Using the free theorem for that type, show that any function
We replace each type variable by a (not yet specified) relation: R for a, S for b and T
for c. The free theorem is:
2
Exercise 8.3 (Skeleton: Evaluator.hs). In the lecture1 , we have developped an evaluator
for the following expression data type:
data Expr
= Lit Integer — a literal
| Expr :+: Expr — addition
| Expr :∗: Expr — multiplication
| Today — some global constant
| Expr :?: Expr — choice
is an exact copy of evaluateA, but additionally supports the global today constant.
The implementation
is an exact copy of evaluateA as well, and comes with additional support for choice.
None of those implementations supports expressions that contain the global today con-
stant and choice at the same time, e.g. Today :?: Lit 42.
We want to implement a function
that supports both the global today constant and choice. The implementation should be
in applicative style such that we can simply copy the first three cases from the evaluateA
implementation. evaluateE uses the Applicative instance for (→) r and evaluateN the one
for [ ], both are predefined in Haskell’s Prelude. We will combine both container types to
a combined one:
type Box r a = r → [a ]
Our Box type synonym combines both effects: The result relies on a global state r and
is nondeterministic ([a ]). Since it is not possible to provide type class instances for type
synonyms, we need to use newtype (or data) to create an actual new type for which we
can instantiate the type class:
1
See in Olat Material/lecture 2021-06-16/solution/InterpreterA.lhs
3
a) Implement instance Functor (Box r ) and instance Applicative (Box r ). We need
Functor since it is a requirement for Applicative.
For a moment, let us assume Box was a type synonym (instead of newtype):
fmap :: (a → b) → (r → [a ]) → (r → [b ])
pure :: a → (r → [a ])
h∗i :: (r → [a → b ]) → (r → [a ]) → (r → [b ])
But this is not the actual type, since now we are missing the Box constructors.
A working implementation relying on the definition of Box is:
But we can also generalize the definition making use of the fact that there are Functor
and Applicative instances for (→) r and [ ]. For (→) r , Haskell predefines fmap = (◦)
and for [ ] the predefined Functor instance is fmap = map.
When considering this general definition, you might wonder why this is not prede-
fined. The answer is: It is actually predefined, you just need to import it:
provides
together with
The instances are implemented exactly as shown above. Instead of our custom type
Box r a we could also use the type Compose ((→) r ) [ ] a and do not need to
implement the Functor and Applicative instances.
4
b) Implement evaluateEN :: Expr → (Integer → [Integer ]). Note that the return type is
Integer → [Integer ], which is almost Box Integer Integer , but not actually the same
since it is a separate type instead of a type synonym. We do not want that the user of
evaluateEN has to deal with the Box layer.
Implement an internal helper function of type Expr → Box Integer Integer that relies
on the Applicative instance for Box r . In evaluateEN you then can call your helper
function and afterwards just get rid of the Box using apply :: Box r a → (r → [a ]).
Alternative solution using the predefined type Compose ((→) r ) [ ] a instead of our
custom type Box r a: