PPL20200629
SCHEME
Define the construct define-with-types, that is used to define a procedure with type constraints, both for the parameters and for the return value. The type constraints are the corresponding type predicates, e.g. number? to check if a value is a number.
If the type constraints are violated, an error should be issued.
E.g.
(define-with-types (add-to-char : integer? (x : integer?) (y : char?))
(+ x (char->integer y)))
defines a procedure called add-to-char, which takes an integer and a character, and returns an integer.
HASKELL
We want to implement a queue, i.e. a FIFO container with the two operations
enqueue and dequeue with the obvious meaning. A functional way of doing this is
based on the idea of using two lists, say L1 and L2, where the first one is used
for dequeuing (popping) and the second one is for enqueing (pushing) When
dequeing, if the first list is empty, we take the second one and put it in the
first, reversing it This last operation appears to be O(n), but suppose we
have n enqueues followed by n dequeues; the first dequeue takes time
proportional to n (reverse), but all the other dequeues take constant time.
This makes the operation O(1) amortised that is why it is acceptable in many
applications.
1) Define Queue and make it an instance of Eq
2) Define enqueue and dequeue, stating their types
HASKELL (ii)
Make Queue an instance of Functor and Foldable
HASKELL (iii)
Make Queue an instance of Applicative
ERLANG
Define a "functional" process buffer, called fuffer, that stores only one value and may receive messages only from its creator. fuffer can receive the following commands:
'set' to store a new value
'get' to obtain the current value
'apply F' to apply the function F to the stored value
'die' to end
'duplicate' to create (and return) an exact copy of itself
SOLUTIONS
(define-syntax define-with-types
(syntax-rules (:)
((_ (f : tf (x1 : t1) ...) e1 ...)
(define (f x1 ...)
(if (and (t1 x1) ...)
(let ((res (begin
e1 ...)))
(if (tf res)
res
(error "bad return type")))
(error "bad input types"))))))
data Queue a = Queue [a] [a] deriving Show
to_list (Queue x y) = x ++ reverse y
instance Eq a => Eq (Queue a) where
q1 == q2 = (to_list q1) == (to_list q2)
enqueue :: a -> Queue a -> Queue a
enqueue x (Queue pop push) = Queue pop (x:push)
dequeue :: Queue a -> (Maybe a, Queue a)
dequeue q@(Queue [] []) = (Nothing, q)
dequeue (Queue (x:xs) v) = (Just x, Queue xs v)
dequeue (Queue [] v) = dequeue (Queue (reverse v) [])
instance Functor Queue where
fmap f (Queue x y) = Queue (fmap f x) (fmap f y)
instance Foldable Queue where
foldr f z q = foldr f z $ to_list q
q1 +++ (Queue x y) = Queue ((to_list q1) ++ x) y
qconcat q = foldr (+++) (Queue [][]) q
instance Applicative Queue where
pure x = Queue [x] []
fs <*> xs = qconcat $ fmap (\f -> fmap f xs) fs
fuffer(Data, PID) ->
receive
{set, PID, V} ->
fuffer(V, PID);
{get, PID} ->
PID!Data, fuffer(Data, PID);
{apply, PID, F} ->
fuffer(F(Data), PID);
{die, PID} -> ok;
{duplicate, PID} ->
PID ! spawn(?MODULE, fuffer, [Data, PID]),
fuffer(Data, PID)
end.