lists and other monoids - ku leuventom.schrijvers/research/...monoids dsls type classes …...
TRANSCRIPT
Lists and Other Monoids Tom Schrijvers
Leuven Haskell User Group
RecursionSchemes
GADTs
Type Families
Monads
Effect Handlers
Data Genericity
Expression Problem
Free Theorems
Lists and Other
Monoids
DSLs
Type Classes
…
Data Genericity
RecursionSchemes
GADTs
Type Families
Monads
Effect Handlers
Data Genericity
Expression Problem
Free Theorems
Lists and Other
Monoids
DSLs
Type Classes
…
Data Genericity
Lists and Other
Monoids
Introduction to Monoids
Abstract Patterns
Abstract Patterns
Math
Haskell’s Math Inspiration
Haskell’s Math Inspiration
Algebra
Haskell’s Math Inspiration
Algebra
Abstract
Haskell’s Math Inspiration
Algebra
Abstract Universal
Haskell’s Math Inspiration
Algebra CategoryTheory
Abstract Universal
Algebra CategoryTheory
Algebra CategoryTheory
regular Haskell monoids
Algebra CategoryTheory
regular Haskell monoids
monoids in the category of
endofunctors
Algebra CategoryTheory
regular Haskell monoids
monoids in the category of
endofunctors
Haskell monads and
applicative functors
The Monoid Structure
4 ingredients
The Monoid Structure
4 ingredients
A set M
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
A set M
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
ℤ = {…,-1,0,1,…}
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
ℤ = {…,-1,0,1,…} + : ℤ × ℤ → ℤ
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
ℤ = {…,-1,0,1,…} + : ℤ × ℤ → ℤ
0 ∈ ℤ
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
ℤ = {…,-1,0,1,…} + : ℤ × ℤ → ℤ
0 ∈ ℤ
Left Unit xε ⨂ x =
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
ℤ = {…,-1,0,1,…} + : ℤ × ℤ → ℤ
0 ∈ ℤ Right Unit x ⨂ ε x=
Left Unit xε ⨂ x =
The Monoid Structure
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
ℤ = {…,-1,0,1,…} + : ℤ × ℤ → ℤ
0 ∈ ℤAssociativity x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
Right Unit x ⨂ ε x=
Left Unit xε ⨂ x =
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
A type M
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
A type M
Int
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
A type M
A function ⨂ :: M → M → M
Int
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
A type M
A function ⨂ :: M → M → M
Int (+) :: Int -> Int -> Int
An element ε :: M
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
A type M
A function ⨂ :: M → M → M
Int (+) :: Int -> Int -> Int
An element ε :: M
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
A type M
A function ⨂ :: M → M → M
Int (+) :: Int -> Int -> Int
0 :: Int
An element ε :: M
Haskell Monoids
4 ingredients
A binary operator ⨂ : M × M → M
An element ε ∈ M
A set M
3 Properties
Left Unit
Right Unit
Associativity
x
x ⨂ ε
x ⨂ (y ⨂ z) (x ⨂ y) ⨂ z=
x
ε ⨂ x
=
=
A type M
A function ⨂ :: M → M → M
3 Properties
Int (+) :: Int -> Int -> Int
0 :: Int
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
A type M
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
A type M
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
An element ε :: M
A type M
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
An element ε :: M
A type M
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
An element ε :: M
A type M
A function ⨂ :: M → M → M
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
An element ε :: M
A type M
A function ⨂ :: M → M → M
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
An element ε :: M
A type M
A function ⨂ :: M → M → M
3 Properties
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
An element ε :: M
A type M
A function ⨂ :: M → M → M
3 Propertiesnot in the Haskell
language
😕
Monoid Type Class
class Monoid m where mempty :: m mappend :: m -> m -> m
(<>) = mappend
Data.Monoid
An element ε :: M
A type M
A function ⨂ :: M → M → M
3 Properties
convenient binary operator
Monoid Instanceclass Monoid m where mempty :: m mappend :: m -> m -> m
instance Monoid Int where mempty = 0 mappend = (+)
Monoid for Bool?
class Monoid m where mempty :: m mappend :: m -> m -> m
instance Monoid Bool where mempty = ??? mappend = ???
Two Possible Instances
instance Monoid Bool where mempty = True mappend = (&&) instance Monoid Bool where mempty = False mappend = (||)
Two Possible Instances
instance Monoid Bool where mempty = True mappend = (&&) instance Monoid Bool where mempty = False mappend = (||)
Two Possible Instances
instance Monoid Bool where mempty = True mappend = (&&) instance Monoid Bool where mempty = False mappend = (||)
Two Possible Instances
instance Monoid Bool where mempty = True mappend = (&&) instance Monoid Bool where mempty = False mappend = (||)
Can’t have two instances for the
same type!!!
Data.Monoid
What's in a name? that which we call a BoolBy any other name would smell as sweet;
Newtype to the Rescue!Data.Monoid
What's in a name? that which we call a BoolBy any other name would smell as sweet;
Newtype to the Rescue!newtype All = All { getAll :: Bool }
instance Monoid All where mempty = All True All x `mappend` All y = All (x && y) newtype Any = Any { getAny :: Bool } instance Monoid Any where mempty = Any False Any x `mappend` Any y = Any (x || y)
Data.Monoid
Newtype to the Rescue!newtype All = All { getAll :: Bool }
instance Monoid All where mempty = All True All x `mappend` All y = All (x && y) newtype Any = Any { getAny :: Bool } instance Monoid Any where mempty = Any False Any x `mappend` Any y = Any (x || y)
Data.Monoid
Both isomorphic to Bool
Newtype to the Rescue!newtype All = All { getAll :: Bool }
instance Monoid All where mempty = All True All x `mappend` All y = All (x && y) newtype Any = Any { getAny :: Bool } instance Monoid Any where mempty = Any False Any x `mappend` Any y = Any (x || y)
Data.Monoid
Newtype to the Rescue!newtype All = All { getAll :: Bool }
instance Monoid All where mempty = All True All x `mappend` All y = All (x && y) newtype Any = Any { getAny :: Bool } instance Monoid Any where mempty = Any False Any x `mappend` Any y = Any (x || y)
Data.Monoid
Newtype to the Rescue!newtype All = All { getAll :: Bool }
instance Monoid All where mempty = All True All x `mappend` All y = All (x && y) newtype Any = Any { getAny :: Bool } instance Monoid Any where mempty = Any False Any x `mappend` Any y = Any (x || y)
Data.Monoid
Two non-conflicting instances
Same Problem for NumSum a
Product a
Data.Monoid
Num a => a
Same Problem for NumSum a
Product a
HomeworkInvent 10 more monoid
structures for Int
Data.Monoid
Num a => a
Applications
The diagrams Package
Brent Yorgey
1
The diagrams Package
Brent Yorgey
=<>
1
The diagrams Package
Brent Yorgey
=<>
`atop`
1
--enable-foo --disable-foo --enable-foo --baz=help
e.g., Command-Line Options:
Duncan Coutts
Compositional Settings2
--enable-foo --disable-foo --enable-foo --baz=help
e.g., Command-Line Options:
Duncan Coutts
Compositional Settings
<>default setting
setting update <><> setting
update…
2
Compositional Settingsdata ConfigFlags = ConfigFlags { foo :: Flag Bool, bar :: Flag PackageDB, baz :: [String] }
2
Compositional Settingsdata ConfigFlags = ConfigFlags { foo :: Flag Bool, bar :: Flag PackageDB, baz :: [String] }
data Flag a = Flag a | Default
instance Monoid (Flag a) where mempty = Default _ `mappend` f@(Flag _) = f f `mappend` Default = f
right biased
2
Compositional Settingsinstance Monoid ConfigFlags where mempty = ConfigFlags { foo = mempty , bar = mempty , baz = mempty } c1 `mappend` c2 = ConfigFlags { foo = foo c1 <> foo c2 , bar = bar c1 <> bar c2 , baz = baz c1 <> baz c2 }
2
Data Aggregation3
Data.Foldable
class Foldable t where foldMap :: Monoid m => (a -> m) -> (t a -> m)
Data Aggregation3
Data.Foldable
class Foldable t where foldMap :: Monoid m => (a -> m) -> (t a -> m)
polymorphic collection
Data Aggregation3
Data.Foldable
toList :: Foldable t => t a -> [a]and :: Foldable t => t Bool -> Boolor :: Foldable t => t Bool -> Boolany :: Foldable t => (a -> Bool) -> t a -> Boolall :: Foldable t => (a -> Bool) -> t a -> Boolsum :: (Foldable t, Num a) => t a -> aproduct :: (Foldable t, Num a) => t a -> amaximum :: (Foldable t, Ord a) => t a -> aminimum :: (Foldable t, Ord a) => t a -> aelem :: (Foldable t, Eq a) => a -> t a -> Bool…
class Foldable t where foldMap :: Monoid m => (a -> m) -> (t a -> m)
polymorphic collection
Data Aggregation3
data Tree a = Empty | Fork (Tree a) a (Tree a)
instance Foldable Tree where foldMap gen Empty = mempty foldMap gen (Fork l x r) = foldMap gen l <> gen x <> foldMap gen r
Data Aggregation3
data Tree a = Empty | Fork (Tree a) a (Tree a)
instance Foldable Tree where foldMap gen Empty = mempty foldMap gen (Fork l x r) = foldMap gen l <> gen x <> foldMap gen r
> sum (Fork (Fork Empty 5 Empty) 3 Empty) 8 > maximum (Fork (Fork Empty 5 Empty) 3 Empty) 5
Data.Foldable
Foldable/Traversable Proposal
3
toList :: Foldable t => t a -> [a]and :: Foldable t => t Bool -> Boolor :: Foldable t => t Bool -> Boolany :: Foldable t => (a -> Bool) -> t a -> Boolall :: Foldable t => (a -> Bool) -> t a -> Boolsum :: (Foldable t, Num a) => t a -> aproduct :: (Foldable t, Num a) => t a -> amaximum :: (Foldable t, Ord a) => t a -> aminimum :: (Foldable t, Ord a) => t a -> aelem :: (Foldable t, Eq a) => a -> t a -> Bool…
Data.Foldable
Foldable/Traversable Proposal
3
toList :: Foldable t => t a -> [a]and :: Foldable t => t Bool -> Boolor :: Foldable t => t Bool -> Boolany :: Foldable t => (a -> Bool) -> t a -> Boolall :: Foldable t => (a -> Bool) -> t a -> Boolsum :: (Foldable t, Num a) => t a -> aproduct :: (Foldable t, Num a) => t a -> amaximum :: (Foldable t, Ord a) => t a -> aminimum :: (Foldable t, Ord a) => t a -> aelem :: (Foldable t, Eq a) => a -> t a -> Bool…
aka Burning Bridges
Proposal
Data.Foldable
Foldable/Traversable Proposal
3
Prelude
toList :: Foldable t => t a -> [a]and :: Foldable t => t Bool -> Boolor :: Foldable t => t Bool -> Boolany :: Foldable t => (a -> Bool) -> t a -> Boolall :: Foldable t => (a -> Bool) -> t a -> Boolsum :: (Foldable t, Num a) => t a -> aproduct :: (Foldable t, Num a) => t a -> amaximum :: (Foldable t, Ord a) => t a -> aminimum :: (Foldable t, Ord a) => t a -> aelem :: (Foldable t, Eq a) => a -> t a -> Bool…
In Prelude as of GHC 7.10
aka Burning Bridges
Proposal
Divide & Conquer
Linear Processing
x1
x2
x3
x4
+
+
+
Linear Processingx1 <> (x2 <> (x3 <> x4))
x1
x2
x3
x4
+
+
+
Linear Processingx1 <> (x2 <> (x3 <> x4))
x1 <> (x2 <> x34)x1
x2
x3
x4
+
+
+
Linear Processingx1 <> (x2 <> (x3 <> x4))
x1 <> (x2 <> x34)
x1 <> (x234)
x1
x2
x3
x4
+
+
+
Linear Processingx1 <> (x2 <> (x3 <> x4))
x1 <> (x2 <> x34)
x1 <> (x234)
x1234
x1
x2
x3
x4
+
+
+
Linear Processingx1 <> (x2 <> (x3 <> x4))
x1 <> (x2 <> x34)
x1 <> (x234)
x1234
x1
x2
x3
x4
+
+
+
n-1 gate delays
Linear Strategy
mconcat :: Monoid m => [m] -> mmconcat = foldr mappend mempty
Data.Monoid
Parallel Processing
x1
x2
x3
x4+
+
+
Parallel Processing(x1 <> x2) <> (x3 <> x4)
x1
x2
x3
x4+
+
+
Parallel Processing(x1 <> x2) <> (x3 <> x4)
x12 <> x34x1
x2
x3
x4+
+
+
Parallel Processing(x1 <> x2) <> (x3 <> x4)
x12 <> x34
x1234
x1
x2
x3
x4+
+
+
Parallel Processing(x1 <> x2) <> (x3 <> x4)
x12 <> x34
x1234
x1
x2
x3
x4+
+
+
log n gate delays
Parallel Strategypconcat :: Monoid m => [m] -> mpconcat [] = memptypconcat [x] = xpconcat xs = (ys `par` zs) `pseq` (ys <> zs) where len = length xs (ys', zs') = splitAt (len `div` 2) xs ys = pconcat ys' zs = pconcat zs'
The List Monoid
The List Monoid
class Monoid m where mempty :: m mappend :: m -> m -> m
instance Monoid [a] where mempty = [] mappend = (++)
Data.Monoid
Equational Reasoning
Left Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
mempty `mappend` ys = {- def. of mempty -} [] `mappend` ys = {- def. of mappend -} [] ++ ys = {- def. of (++) -} ys
Proof Style:EquationalReasoning
Left Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
mempty `mappend` ys = {- def. of mempty -} [] `mappend` ys = {- def. of mappend -} [] ++ ys = {- def. of (++) -} ys
Proof Style:EquationalReasoning
Left Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
mempty `mappend` ys = {- def. of mempty -} [] `mappend` ys = {- def. of mappend -} [] ++ ys = {- def. of (++) -} ys
Proof Style:EquationalReasoning
Left Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
mempty `mappend` ys = {- def. of mempty -} [] `mappend` ys = {- def. of mappend -} [] ++ ys = {- def. of (++) -} ys
Proof Style:EquationalReasoning
Left Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
mempty `mappend` ys = {- def. of mempty -} [] `mappend` ys = {- def. of mappend -} [] ++ ys = {- def. of (++) -} ys
Proof Style:EquationalReasoning
Left Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
mempty `mappend` ys = {- def. of mempty -} [] `mappend` ys = {- def. of mappend -} [] ++ ys = {- def. of (++) -} ys
Proof Style:EquationalReasoning
Right Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
l ++ [] = l
Right Unit Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
l ++ [] = l
Proof Style:Structural Induction
+EquationalReasoning
Base Case: l = []
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
[] ++ [] = {- def. of (++) -} []
Proof Style:Structural Induction
+EquationalReasoning
Base Case: l = []
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
[] ++ [] = {- def. of (++) -} []
Proof Style:Structural Induction
+EquationalReasoning
Inductive Case: l = x:xs
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
(x:xs) ++ [] = {- def. of (++) -} x : xs ++ [] = {- ind. hypot. -} x:xs
Proof Style:Structural Induction
+EquationalReasoning
Inductive Case: l = x:xs
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
(x:xs) ++ [] = {- def. of (++) -} x : xs ++ [] = {- ind. hypot. -} x:xs
Proof Style:Structural Induction
+EquationalReasoning
xs ++ [] = xsInduction Hypothesis
Inductive Case: l = x:xs
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
(x:xs) ++ [] = {- def. of (++) -} x : xs ++ [] = {- ind. hypot. -} x:xs
Proof Style:Structural Induction
+EquationalReasoning
xs ++ [] = xsInduction Hypothesis
Inductive Case: l = x:xs
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
(x:xs) ++ [] = {- def. of (++) -} x : xs ++ [] = {- ind. hypot. -} x:xs
Proof Style:Structural Induction
+EquationalReasoning
xs ++ [] = xsInduction Hypothesis
Inductive Case: l = x:xs
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
(x:xs) ++ [] = {- def. of (++) -} x : xs ++ [] = {- ind. hypot. -} x:xs
Proof Style:Structural Induction
+EquationalReasoning
xs ++ [] = xsInduction Hypothesis
Associativity Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
xs ++ (ys ++ zs) = (xs ++ ys) ++ zs
Proof Style:Structural Induction
+EquationalReasoning
Associativity Proof
[] ++ ys = ys (x:xs) ++ ys = x : xs ++ ys
xs ++ (ys ++ zs) = (xs ++ ys) ++ zs
Proof Style:Structural Induction
+EquationalReasoning
Homework
The Free Monoid
Monoid (Homo)morphisma function between monoids
f :: M1 -> M2
f mempty = mempty f (x <> y) = f x <> f y
such that:
and:
length (x ++ y) = length x + length y
length [] = 0
length :: [a] -> Int
Monoid (Homo)morphisma function between monoids
such that:
and:
Free Monoid
A
M
gen
Free Monoid
A
M
gen FreeMonoid
Free Monoid
A
M
gen FreeMonoid
homomorphism
Free Monoid
A
M
gen FreeMonoid
inj
homomorphism
Free Monoid
A
M
gen
inj
homomorphism
[A]
Free Monoid
A
M
gen
homomorphism
[A]
\x -> [x]
Free Monoid
A
M
gen [A]
\x -> [x]
mconcat . map gen
What is a Data.Foldable?
T a
What is a Data.Foldable?
T a
m
foldMap gen
Data structures that support some
abstract nonsense?
What is a Data.Foldable?
T a
[a]
toList
Data structures that
support a list view!
m
foldMap gen
Data structures that support some
abstract nonsense?
What is a Data.Foldable?
T a
mconcat . map gen
[a]
toList
Data structures that
support a list view!
m
foldMap gen
Data structures that support some
abstract nonsense?
What is a Data.Foldable?
T a
mconcat . map gen
[a]
toList
Data structures that
support a list view!
m
foldMap gen
Data structures that support some
abstract nonsense?
(Potentially)more efficient
Summary
Monoids
★ Simple concept from Algebra
★ Ubiquitous in Haskell
★ Cool Applications
★ List is the Free Monoid
Next time: 5/5/2015
Recursion Schemes
GADTs
Type Families
Monads
Effect Handlers
Data Genericity
Expression Problem
Free Theorems
DSLs
Type Classes
…
Data Genericity
RecursionSchemes
Lists and other
Monoids
Recursion Schemes
GADTs
Type Families
Monads
Effect Handlers
Data Genericity
Expression Problem
Free Theorems
DSLs
Type Classes
…
Data Genericity
RecursionSchemes
Lists and other
Monoids
GADTs
Type Families
Type Classes
Join the Google Group
Leuven Haskell User Group