Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Marco Comini
3 gennaio 2008
1 Esempietti
1.1 Numeri e Liste
1. In questo esempio generiamo la lista dei primi numeri primi minori di n,
con un algoritmo non troppo efficiente ma molto semplice da scrivere.
eratostene n = 1: era [ 2 . . n ]
where
era [ ] = [ ]
e r a ( x : xs )
| x∗x < n = e r a ys
| otherwise = ys
where
ys = f i l t e r ( \ y−>y ‘rem ‘ x /= 0 ) xs
si noti come nello scope del where è visibile la n del pattern di definizione.
c n t 2 l i s t xs ( a , b , f )
| a > b = xs
| otherwise = c n t 2 l i s t ( put ( f b ) xs ) ( a , pred b , f )
where
put 0 ys = ys
put n ys = b : put ( n−1) ys
1.2 Alberi
Si definiscano gli Alberi Binari di Ricerca col seguente tipo di dato astratto
(polimorfo)
data (Ord a , Show a , Read a ) => BST a = Void | Node a (BST a ) (BST a )
deriving (Eq, Ord, Read , Show)
e si usi (per comodità) lo stesso tipo di dato anche per Alberi Binari normali.
1.3 Matrici
Implementiamo le matrici si implementano come liste di liste, per righe. Quindi
1 2 3 4
5 6 7 8
9 10 11 12
2
module B i n a r y T r e e s ( Tree ( . . ) ,
empty ,
fold ,
isEmpty ,
new ,
t o L i s t ) where
−− E x p o r t e d f u n c t i o n s
empty : : Tree a
empty = Void
−−− Not e x p o r t e d f u n c t i o n s
sum = f o l d ( \ x y z−>x+y+z ) 0
3
where
filteredsum x y z
| p x = x + y + z
| otherwise = y + z
2.2 BinarySearchTrees.hs
Qui si mostra come riutilizzare un altro ADT (Abstract Data Type) per imple-
mentarne uno nuovo, esportando metodi del vecchio (eventualmente cambiando
i nomi) e/o aggiungendo nuovi metodi.
module B i n a r y S e a r c h T r e e s (BST,
elem ,
empty ,
fold ,
fromList ,
fromListUnique ,
insert ,
insertUnique ,
isEmpty ,
join ,
joinUnique ,
meet ,
sort ,
t o L i s t ) where
−− E x p o r t e d f u n c t i o n s
4
insertUnique : : (Ord a ) => a −> BST a −> BST a
i n s e r t U n i q u e x Void = Node x Void Void
i n s e r t U n i q u e x n@( Node y l r )
| x==y = n
| x<y = Node y ( i n s e r t U n i q u e x l ) r
| otherwise = Node y l ( i n s e r t U n i q u e x r )
5
isEmpty ,
fold ,
lookup ,
toList ,
update ,
join ,
fromList ,
sort ,
meet ,
mapMonotone ,
map,
delete ,
diff ,
findMin ,
findMax ) where
insEq = (==)
valJoin x = x
valMeet x = x
6
showsTree ( Node c x l r ) = ( ’ ( ’ : ) .
showsTree l . ( ’ ’ : ) .
shows x . ( ’ : ’ : ) . shows c . ( ’ ’:) .
showsTree r .
( ’) ’:)
fold : : (Ord’ a ) => ( a −> b −> b −> b ) −> b −> RBT a −> b
fold z Void = z
f o l d f z ( Node x l r ) = f x ( fold f z l ) ( fold f z r )
−− i n t h e f o l l o w i n g f u n c t i o n we can s e e how t h e p o t e n t i a l d i f f e r e n c e s
−− b e t w e e n == and ‘ insEq ‘ do i n t e r a c t , s i n c e we cannot assume t h a t i n c a s e
−− o f e q u a l i t y we can j u s t r e t u r n ( y : x s )
7
join : : (Ord’ a ) => RBT a −> RBT a −> RBT a
j o i n t 1 t 2 = f o l d a g g r id t 2 t 1
where
−− a g g r : : ( Ord ’ a ) => a −> (RBT a −> RBT a ) −> (RBT a −> RBT a ) −> RBT a
−> RBT a
a g g r x l a c c r a c c = l a c c . update x . r a c c
−− i f f u n c t i o n i s monotone t h e n t h e t r e e s t r u c t u r e i s p r e s e r v e d t h u s we can
−− a p p l y t h e f u n c t i o n d i r e c t l y i n node v a l u e s ( cannot u s e f o l d c a u s e i t l o o s e s
color )
−− o t h e r w i s e we have t o r e c o n s t r u c t a new t r e e e n t i r l y
8
diff : : (Ord’ a ) => RBT a −> RBT a −> RBT a
d i f f t 1 t 2 = f o l d a g g r id t 1 t 2
where
a g g r x l a c c r a c c = l a c c . delete x . r a c c
{−
− findMin :: ( Ord ’ a ) => RBT a −> a
− findMin ( Node x Void ) = x
− findMin ( Node l ) = findMin l
− findMin Void = e r r o r ” RedBlackTrees . findMin : empty t r e e has no
minimal e l e m e n t ”
−
− findMax :: ( Ord ’ a ) => RBT a −> a
− findMax ( Node x Void ) = x
− findMax ( Node r) = findMax r
− findMax Void = e r r o r ” RedBlackTrees . findMax : empty t r e e has no
maximal e l e m e n t ”
−}
−−− Not e x p o r t e d
9
27 ,
−−− Okasaki ” P u r e l y F u n c t i o n a l Data S t r u c t u r e s ”
b a l a n c e L : : (Ord’ a ) => RBT a −> RBT a
balanceL t r e e
| i s R e d l e f t T r e e && i s R e d ( l e f t l e f t T r e e )
= l e t Node z ( Node y ( Node x a b) c ) d = tree
in Node Red y ( Node Black x a b ) ( Node Black z c d )
| i s R e d l e f t T r e e && i s R e d ( r i g h t l e f t T r e e )
= l e t Node z ( Node x a ( Node y b c) ) d = tree
in Node Red y ( Node Black x a b ) ( Node Black z c d )
| otherwise
= tree
where
leftTree = left tree
| i s R e d r i g h t T r e e && i s R e d ( l e f t r i g h t T r e e )
= l e t Node x a ( Node z ( Node y b c ) d) = tree
in Node Red y ( Node Black x a b ) ( Node Black z c d )
| otherwise
= tree
where
rightTree = right tree
−−− b a l a n c i n g a f t e r d e l e t i o n
10
d e l B a l a n c e R : : (Ord’ a ) => RBT a −> RBT a
delBalanceR t r e e
| isDoublyBlack ( r i g h t t r e e ) = r e v i s e R i g h t t r e e
| otherwise = tree
where
reviseRight tree
| l==Void = t r e e
| i s b l a c k l && i s R e d ( l e f t l )
= l e t Node c o l x ( Node y ( Node z d c ) b) a = tree
in Node c o l y ( Node Black z d c ) ( Node Black x b ( s i n g l e B l a c k a ) )
| i s b l a c k l && i s R e d ( r i g h t l )
= l e t Node c o l x ( Node z d ( Node y c b) ) a = tree
in Node c o l y ( Node Black z d c ) ( Node Black x b ( s i n g l e B l a c k a ) )
| isblackl
= l e t Node c o l x ( Node y c b) a = tree
in Node ( i f c o l==Red then Black e l s e DoublyBlack ) x ( Node Red y c b )
( singleBlack a)
| otherwise
= l e t Node x ( Node y c b) a = tree
in Node Black y c ( r e v i s e R i g h t ( Node Red x b a ) )
where
l = l e f t tree
isblackl = isBlack l
4 Sets e MultiSets
4.1 Sets.hs
Qui l’interessante per prima cosa è la definizione del tipo Set a con le varie
istanze per usare opportunamente RBT, oltre che l’istanza Eq (Set a).
Inoltre è interessante la ri-definizione delle istanze di Show e Read che an-
dremmo a ereditare da RBT. Una nota d’attenzione merita l’accorgimento per
mettere il giusto numero di , fra gli elementi di un insieme.
Svariati metodi di RBT vengono nascosti mentre molte operazioini tipiche
degli insiemi vengono introdotte mediante opportune fold.
module S e t s ( Set ,
(\\) ,
delete ,
difference ,
elem ,
empty ,
filter ,
findMax ,
findMin ,
fold ,
fromList ,
insert ,
intersection ,
intersections ,
isEmpty ,
isProperSubsetOf ,
isSubsetOf ,
map,
mapMonotone ,
singleton ,
size ,
toList ,
union ,
11
u n i o n s ) where
−− E x p o r t e d f u n c t i o n s
12
empty : : Ord a => S e t a
empty = MakeSet RBT. empty
13
d i f f e r e n c e ( MakeSet t 1 ) ( MakeSet t 2 ) = MakeSet (RBT. d i f f t 2 t 1 )
i n f i x l 9 \\
−−− Not e x p o r t e d f u n c t i o n s
{− TO DO
partition : : Ord a => ( a −> Bool ) −> S e t a −> ( S e t a , S e t a )
d e l e t e M i n : : S e t a −> S e t a
d e l e t e M a x : : S e t a −> S e t a
d e l e t e F i n d M i n : : S e t a −> ( a , S e t a )
d e l e t e F i n d M a x : : S e t a −> ( a , S e t a )
−}
4.2 MultiSets.hs
Questo modulo è praticamente identico al precedente a parte l’istanza Ord’ (Val a
) che ci obbliga a inserire elementi uguali più volte generando quindi multinsiemi.
Ovviamente vale solo come esempio visto che tenere i duplicati è sicuramente il
metodo più inefficiante per impelmentare multinsiemi.
module M u l t i S e t s ( M u l t i S e t ,
(\\) ,
delete ,
difference ,
elem ,
empty ,
filter ,
14
findMax ,
findMin ,
fold ,
fromList ,
insert ,
intersection ,
intersections ,
isEmpty ,
isProperSubsetOf ,
isSubsetOf ,
map,
mapMonotone ,
singleton ,
size ,
toList ,
union ,
u n i o n s ) where
a g g r x l a c c r a c c = l a c c . shows x . comma r a c c
15
readsPrec = readsSet
where
r e a d s S e t t s = [ ( MakeSet t , vs ) | ( ” { ” , us ) <− lex t s ,
( t , vs ) <− r e a d l us ]
type S e t a = M u l t i S e t a
−− E x p o r t e d f u n c t i o n s
16
map f ( MakeSet t ) = MakeSet (RBT.map f ’ t )
where
f ’ ( SetValue x ) = SetValue ( f x )
i n f i x l 9 \\
−−− Not e x p o r t e d f u n c t i o n s
4.3 MultiSetsCompact.hs
Qui implementiamo multinsiemi più astutamente come coppie (valore,numero di
ripetizioni). Si vedano le dichiarazioni delle istanze (specialmente Ord’ (Val a),
Ord (Val a) e Show (Val a)).
module MultiSetsCompact ( M u l t i S e t ,
(\\) ,
delete ,
difference ,
elem ,
empty ,
17
filter ,
findMax ,
findMin ,
fold ,
fromList ,
insert ,
intersection ,
intersections ,
isEmpty ,
isProperSubsetOf ,
isSubsetOf ,
map,
mapMonotone ,
singleton ,
size ,
toList ,
union ,
u n i o n s ) where
18
newtype M u l t i S e t a = MakeSet (RBT ( Val a ) )
a g g r x l a c c r a c c = l a c c . shows x . comma r a c c
type S e t a = M u l t i S e t a
−− E x p o r t e d f u n c t i o n s
19
f r o m L i s t = MakeSet . ( f o l d l update ’ RBT. empty )
where
update ’ t x = RBT. update ( MSetVal x 1 ) t
d e l : : (Ord a ) => Int −> a −> RBT ( Val a ) −> RBT ( Val a )
del n x t
| m> 0 = t1
| otherwise = t 2
where
t 1 = RBT. update ( MSetVal x (−n ) ) t
( MSetVal m) = head (RBT. lookup ( MSetVal x ( error ” MultiSetsCompact . d e l :
i n t e r n a l e r r o r ” ) ) t1 )
t 2 = RBT. delete ( MSetVal x m) t 1
20
i n f i x l 9 \\
−−− Not e x p o r t e d f u n c t i o n s
4.4 Tables.hs
Con poco sforzo si possono implementare Tabelle Associative da a a b, che son
poi funzioni da a in b, che andiamo a mantenere estensionalmente. Qui la cosa
interessante è la lookup che deve restituire Maybe b invece di [b].
module T a b l e s ( Table ,
empty ,
filter ,
findMax ,
findMin ,
fold ,
fromList ,
isEmpty ,
lookup ,
map,
mapMonotone ,
merge ,
merges ,
remove ,
size ,
toList ,
update ) where
21
data (Ord a ) => Val a b = TableValue a b
−− E x p o r t e d f u n c t i o n s
22
empty : : Ord a => Table a b
empty = Table RBT. empty
cnv [ ] = Nothing
cnv [ TableValue k ’ v ]
| k == k ’ = Just v
| otherwise = error ” Table . l o o k u p : l o o k u p mismatch ”
cnv = error ” Table . l o o k u p : non−d e t e r m i n i s t i c l o o k u p ”
23
remove : : Ord a => a −> Table a b −> Table a b
remove k ( Table t ) = Table (RBT. delete ( TableValue k ( error ” Table . d e l :
internal error ”) ) t )
−−− Not e x p o r t e d f u n c t i o n s
24