Finger Trees in Haskell - Technische Universität München

Werbung
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Finger Trees
in Haskell
Andreas Bergmaier
Technische Universität München
Seminar Fortgeschrittene Konzepte der funktionalen Programmierung“
”
Sommmersemester 2015
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
2,3-Bäume
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
2,3-Bäume
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
2,3-Bäume
Finger Trees
in Haskell
Andreas Bergmaier
data Node a = Node2 a a | Node3 a a a
1
Einführung
2
2,3-Bäume
data Tree a = Zero a | Succ ( Tree ( Node a ))
3
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Node (Node (Node a)))
Node (Node a)
Node a
a
Finger Trees
in Haskell
Monoid
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
neutrales Element
mempty ‘mappend‘ a = a = a ‘mappend‘ mempty
assoziative Verknüpfung
(a ‘mappend‘ b) ‘mappend‘ c = a ‘mappend‘ (b ‘mappend‘ c)
1
2
3
class Monoid a where
mempty :: a
mappend :: a -> a -> a
4
5
6
mconcat :: [ a ] -> a
mconcat = foldr mappend mempty
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Foldable
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
1
2
3
class Foldable t where
foldMap :: Monoid m = > ( a -> m ) -> t a -> m
foldMap f = foldr ( mappend . f ) mempty
4
5
foldr :: ( a -> b -> b ) -> b -> t a -> b
Split
Anwendungen
Finger Trees
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Idee
Konstanter Zugriff auf Enden
Amortisiert konstante cons und snoc
Vom 2,3-Baum zum Finger Tree
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Vom 2,3-Baum zum Finger Tree
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Vom 2,3-Baum zum Finger Tree
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Vom 2,3-Baum zum Finger Tree
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees
in Haskell
Finger Trees
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Idee
Konstanter Zugriff auf Enden
Annotierung
Split
Anwendungen
Struktur
1
2
3
4
data Digit a =
|
|
|
One a
Two a a
Three a a a
Four a a a a
5
6
7
data FingerTree a = Empty | Single a
| Spine ( Digit a ) ( FingerTree ( Node a )) ( Digit a )
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
a
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
1
2
3
4
5
6
7
8
9
10
11
12
13
<|
(| >) :: FingerTree a -> a -> FingerTree a
Empty | > a
= Single a
( Single a ) | > b
= Spine ( One a )
Empty ( One b )
( Spine l m ( One a )) | > b
= Spine l m
( Two a b )
( Spine l m ( Two a b )) | > c
= Spine l m
( Three a b c )
( Spine l m ( Three a b c )) | > d = Spine l m
( Four a b c d )
( Spine l m ( Four a b c d )) | > e = Spine l
( m | > Node3 a b c )
( Two d e )
symmetrisch zu |>
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees - Aufbau
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
1
2
3
( < <|) :: Foldable f = >
f a -> FingerTree a -> FingerTree a
( < <|) = flip $ foldr ( <|)
4
5
6
7
(| > >) :: Foldable f = >
FingerTree a -> f a -> FingerTree a
(| > >) = foldl (| >)
8
9
fromList = ( < <| Empty )
Annotierung
Split
Anwendungen
Finger Trees - Konkatenation
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
1
2
3
4
5
6
7
8
9
10
11
12
app :: FingerTree a -> [ a ] -> FingerTree a
-> FingerTree a
app Empty ns rs
= ns < <| rs
app ls ns Empty
= ls | > > ns
app ( Single l ) ns rs = l <| ( ns < <| rs )
app ls ns ( Single r ) = ( ls | > > ns ) | > r
app ( Spine prl tl sfl ) ns ( Spine prr tr sfr ) =
Spine prl
( app tl
( nodes $ toList sfl ++ ns ++ toList prr )
tr )
sfr
13
14
15
16
17
18
nodes
nodes
nodes
nodes
nodes
:: [ a ] -> [ Node a ]
( a : b :[])
= Node2
( a : b : c :[])
= Node3
( a : b : c : d :[]) = Node2
( a : b : c : ns )
= Node3
a
a
a
a
b
: []
b c : []
b
: Node2 c d : []
b c : nodes ns
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Finger Trees - Konkatenation
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
1
2
3
instance Monoid ( FingerTree a ) where
mempty = Empty
mappend a b = app a [] b
Annotierung
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Struktur
1
data Node m a = Node2 ! m a a | Node3 ! m a a a
2
3
4
5
6
7
data FingerTree m a = Empty | Single ! m a
| Spine ! m
!( Digit a )
( FingerTree m ( Node m a ))
!( Digit a )
Annotierung
Split
Anwendungen
Annotierung
Finger Trees
in Haskell
Andreas Bergmaier
Idee
Einführung
2,3-Bäume
Finger Trees
1
2
class Monoid m = > Measured v m where
measure :: v -> m
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Beispiele
1
2
3
instance Monoid m = > Measured ( Node m a ) m where
measure ( Node2 m _ _ ) = m
measure ( Node3 m _ _ _ ) = m
4
5
6
7
8
instance Monoid m = > Measured ( FingerTree m a ) m where
measure Empty = mempty
measure ( Single m _ ) = m
measure ( Spine m _ _ _ ) = m
9
10
11
instance Measured a m = > Measured ( Digit a ) m where
measure = mconcat . map measure . toList
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
1
2
3
4
5
6
7
8
9
10
11
12
split :: Measured a m = >
( m -> Bool ) -> FingerTree m a ->
Maybe ( FingerTree m a , a , FingerTree m a )
split _
Empty
= Nothing
split pred t | pred mempty
= Nothing
| not ( pred mall ) = Nothing
| otherwise
= Just $ splitFrom
pred
mempty
t
where
mall = measure t
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
1
2
3
4
5
6
7
8
9
splitList :: Measured a m = >
( m -> Bool ) -> m -> [ a ] -> ([ a ] , a , [ a ])
splitList pred _
[x]
= ([] , x , [])
splitList pred acc ( x : xs ) = if pred acc ’
then ([] , x , xs )
else ( x : xs ’ , x ’ , rs ’)
where
acc ’ = acc ‘ mappend ‘ measure x
( xs ’ , x ’ , rs ’) = splitList acc ’ xs
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
splitNode :: Measured a m = >
( m -> Bool ) -> m -> Node m a -> ([ a ] , a , [ a ])
splitNode pred acc ( Node2 _ a b )
=
let aacc = acc ‘ mappend ‘ measure a
in if pred aacc
then ([] , a , [ b ])
else ([ a ] , b , [])
splitNode pred acc ( Node3 _ a b c ) =
let aacc = acc ‘ mappend ‘ measure a
bacc = aacc ‘ mappend ‘ measure b
in if pred aacc
then ([] , a , [b , c ])
else if pred bacc
then ([ a ] , b , [ c ])
else ([ a , b ] , c , [])
Finger Trees
in Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Andreas Bergmaier
splitFrom :: Measured a m = >
( m -> Bool ) -> m -> FingerTree m a
Einführung
-> ( FingerTree m a , a , FingerTree m a )
2,3-Bäume
splitFrom pred acc ( Single _ x ) = ( Empty , x , Empty )
Finger Trees
splitFrom pred acc ( Spine _ pr t sf )
Idee
Aufbau
| pred pracc = let ( ls , x , rs ) =
Konkatenation
splitFoldable pred acc pr
Annotierung
in ( fromList ls , x , spineL rs t sf )
Split
| pred tacc = let ( lt , ts , rt ) =
Anwendungen
splitFrom pred pracc t
prlacc = pracc ‘ mappend ‘ measure lt
( ls , x , rs ) =
splitFoldable pred prlacc ts
in ( spineR pr lt ls ,
x,
spineL rs rt sf )
| otherwise = let ( ls , x , rs ) =
splitFoldable pred tacc sf
in ( spineR pr t ls , x , fromList rs )
where
pracc = acc ‘ mappend ‘ measure pr
tacc = pracc ‘ mappend ‘ measure t
Anwendungen
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
Finger Trees
Beispiele
Idee
Aufbau
Konkatenation
Annotierung
Indexed Sequence
Ordered Sequence
Priority Queue
Interval Tree
1
newtype Elem a = Elem { getElem :: a }
2
3
instance Measured ( Elem a ) ... where
Split
Anwendungen
Indexed Sequence
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
1
2
3
4
5
6
1
2
−− from Data . Monoid
−− Monoid under addition
newtype Sum a = Sum { getSum :: a }
instance Num a = > Monoid ( Sum a ) where
mempty = Sum 0
Sum x ‘ mappend ‘ Sum y = Sum ( x + y )
instance Measured ( Elem a ) ( Sum Int ) where
measure ( Elem _ ) = Sum 1
3
4
5
6
at :: Int -> FingerTree ( Sum Int ) ( Elem a ) -> Maybe a
at i t = fmap (\( _ ,x , _ ) - > getElem x )
( split (( > i ) . getSum ) t )
7
8
9
length :: FingerTree ( Sum Int ) ( Elem a ) -> Int
length = getSum . measure
Finger Trees
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
MaxPriority Queue
Finger Trees
in Haskell
Andreas Bergmaier
Einführung
2,3-Bäume
1
data Prio a = NegInfinity | Prio a deriving ( Eq , Ord , Show
Finger )
Trees
2
3
4
5
6
7
1
2
instance ( Ord a ) = > Monoid ( Prio a ) where
mempty = NegInfinity
mappend NegInfinity x = x
mappend x NegInfinity = x
mappend ( Prio a ) ( Prio b ) = Prio ( a ‘max ‘ b )
instance Ord a = > Measured ( Elem a ) ( Prio a ) where
measure ( Elem x ) = Prio x
3
4
5
6
7
8
9
extract :: Ord a = > FingerTree ( Prio a ) ( Elem a )
-> Maybe (a , FingerTree ( Prio a ) ( Elem a ))
extract t = fmap (\( l ,x , r ) -> ( getElem x , mappend l r ))
( split ( >= max ) t )
where
max = measure t
Idee
Aufbau
Konkatenation
Annotierung
Split
Anwendungen
Herunterladen