riccardotommasini / ppl

This repository contains the material related to the practical classes of the course Principles of Programming Languages
Apache License 2.0
29 stars 12 forks source link

Soluzioni tema d'esame 8.2.2019 #18

Open drblallo opened 5 years ago

drblallo commented 5 years ago

Buongiorno, ho letto le soluzioni dell'esercizio di haskell e mi sembra di capire che tale versione non rispetti la interchange law (http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Applicative.html) degli applicative:

La definizione è questa:

instance Applicative BFlist where
    pure x = BFlist Fwd [x]
    x <*> y = bflconcatmap (\f -> fmap f y) x

Pure crea una BFlist in direzione forward, come ci si aspetta, mentre <*> invoca bflconcatmap passando come argomenti x e una lambda. Questa lambda utilizza fmap delle BFList, definita come

    fmap f (BFlist d x) = BFlist d (fmap f x)

Poichè fmap non può cambiare la direzione della lista si ha che la lambda utilizzata nella definizione di applicative può esclusivamente ritornare bflist che hanno la stessa direzione di y.

Questa lambda è utilizzata in bflconcatmap

    bflconcatmap f x = bflconcat $ fmap f x

bflconcatmap invoca bflconcat passando come argomento fmap f x. Come prima, questa fmap può solo ritornare una lista che ha la stessa direzione di X. Questo implica l'argomento di bflconcat diventa (BFlist (DIR_X) [(BFlist (DIR_Y) [content]), ...]). Cioè una BFList che ha la direzione di x e che contiene delle bflist che hanno la direzione di y.

A questo punto bflconcat, definita come:

bflconcat (BFlist d v) = foldr (<++>) (BFlist d []) (BFlist d v)

invoca foldr, la quale opera all'interno della bflist più esterna, e ragiona esclusivamente sulle liste interne, concatenandole. La conseguenza è che la direzione di x è ignorata al fine di calcolare il risultato e la direzione sarà sempre uguale a quella di y, e la concatenazione delle liste interne avviene come una concatenazione comune, perchè tutte le direzioni sono uguali.

Infatti, testandolo risulta

*SOLUTION> bb = (BFlist Bwd [(+1), (+2), (+3)])
*SOLUTION> bf = (BFlist Fwd [(+1), (+2), (+3)])
*SOLUTION> bf <*> (BFlist Fwd x)
+[2,3,4,3,4,5,4,5,6]
*SOLUTION> bf <*> (BFlist Bwd x)
-[2,3,4,3,4,5,4,5,6] 
*SOLUTION> bb <*> (BFlist Fwd x)
+[2,3,4,3,4,5,4,5,6]
*SOLUTION> bb <*> (BFlist Bwd x)
-[2,3,4,3,4,5,4,5,6]      

ma questa è una violazione delle leggi degli applicative, poichè dovrebbero rispettare

u <*> pure y = pure ($ y) <*> u 
(oppure u <*> pure x = pure (\f -> f x) <*> u)

u <*> pure y avrà sempre una direzione pari a Fwd, poichè pure inizializza il membro a destra con tale valore. Mentre pure ($ y) <*> u avrà sempre una direzione pari a quella di u. Il che significa che se u è uguale a (BFlist Bwd Content) allora la legge non è rispettata.

è questo ragionamento corretto o esiste un qualche passaggio che non ho compreso?

Distinti saluti.