#Polycephaly Or, multiplying instance heads
layout: false .left-column[
] .right-column[
class Print a where { print :: a -> String }
instance Show a => Print a where { print = show }
instance Print a where { print = "No show" }
???
Doesn't work.
Example of usefulness: serialization
General principle: reflecting class-instance info into value (or type) level
layout: false .left-column[
] .right-column[
class Print a where { print :: a -> String }
instance Show a => Print a where { print = show }
instance Print a where { print = "No show" }
Duplicate instance declarations:
instance Show a => Print a -- Defined at ex1.hs:4:10
instance Print a -- Defined at ex1.hs:5:20
Failed, modules loaded: none
]
.left-column[
] .right-column[
class Print a where { print :: a -> String }
instance Show a => Print a where { print = show }
instance Print a where { print = "No show" }
Duplicate instance declarations:
instance Show a => Print a -- Defined at ex1.hs:4:10
instance Print a -- Defined at ex1.hs:5:20
Failed, modules loaded: none
layout: false .left-column[
] .right-column[
class Print a where { print :: a -> String }
instance Show a => Print a where { print = show }
instance Print a where { print = "No show" }
layout: false .left-column[
] .right-column[
.small[
class Print a where { print :: a -> String }
instance Show a => Print a where { print = show }
instance Print a where { print = "No show" }
-- Context/constraint Class method
-- | |
-- ↓ ↱ Context arrow ↓
instance Show a => Print a where { print = show }
instance Print a where { print = "No show" }
-- ↑
-- Instance head
]
layout: false .left-column[
] .right-column[
class A a
class B a
class C a
instance (Show a) => A a where {...}
instance A a where {...}
instance (A a) => B a where {...}
instance B a where {...}
instance (B a) => C a where {...}
instance C a where {...}
layout: false .left-column[
] .right-column[
class A a
class B a
class C a
instance (Show a) => A a where {...}
instance A a where {...}
instance (A a) => B a where {...}
instance B a where {...}
instance (B a) => C a where {...}
instance C a where {...}
layout: false .left-column[
] .right-column[ Which one to pick?
instance P a => A a where { amethod = ...}
instance Q a => A a where { amethod = ...}
instance R a => A a where { amethod = ...}
]
layout: false .left-column[
] .right-column[ Which one to pick?
instance P a => A a where { amethod = ...}
instance Q a => A a where { amethod = ...}
instance R a => A a where { amethod = ...}
Prolog's answer:
A(a) :- P(a).
A(a) :- Q(a).
A(a) :- R(a).
layout: false .left-column[
] .right-column[ Which one to pick?
instance P a => A a where { amethod = ...}
instance Q a => A a where { amethod = ...}
instance R a => A a where { amethod = ...}
Prolog's answer: The first
A(a) :- P(a).
A(a) :- Q(a).
A(a) :- R(a).
layout: false .left-column[
] .right-column[ Which one to pick?
instance P a => A a where { amethod = ...}
instance Q a => A a where { amethod = ...}
instance R a => A a where { amethod = ...}
Prolog's answer: The first
A(a) :- P(a).
A(a) :- Q(a).
A(a) :- R(a).
layout: false .left-column[
] .right-column[ Which one to pick?
instance P a => A a where { amethod = ...}
instance Q a => A a where { amethod = ...}
instance R a => A a where { amethod = ...}
Prolog's answer: The first
A(a) :- P(a).
A(a) :- Q(a).
A(a) :- R(a).
But:
- Sometimes it matters. ]
layout: false .left-column[
] .right-column[ Which one to pick?
instance P a => A a where { amethod = ...}
instance Q a => A a where { amethod = ...}
instance R a => A a where { amethod = ...}
Prolog's answer: The first
A(a) :- P(a).
A(a) :- Q(a).
A(a) :- R(a).
But:
- Sometimes it matters.
A(X) :- P(X).
A(X) :- Q(X).
A(X) :- R(X).
P(alice).
Q(bob).
R(carol).
?- A(X).
layout: false .left-column[
] .right-column[ Which one to pick?
instance P a => A a where { amethod = ...}
instance Q a => A a where { amethod = ...}
instance R a => A a where { amethod = ...}
Prolog's answer: The first
A(a) :- P(a).
A(a) :- Q(a).
A(a) :- R(a).
But:
- Sometimes it matters.
A(X) :- P(X).
A(X) :- Q(X).
A(X) :- R(X).
P(alice).
Q(bob).
R(carol).
?- A(X).
- And then this ends up looking too procedural!
layout: false .left-column[
layout: false .left-column[
] .right-column[
- Add an extra parameter! ]
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a where { ... }
instance Show a => PrintHelper T1 a
instance PrintHelper T2 a
instance PrintHelper flag a => Print a where { ... }
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a where { ... }
instance Show a => PrintHelper T1 a
instance PrintHelper T2 a
-- vv --
instance PrintHelper flag a => Print a where { ... }
-- ^^ --
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a where { ... }
instance Show a => PrintHelper T1 a
instance PrintHelper T2 a
-- vv --
instance PrintHelper flag a => Print a where { ... }
-- ^^ --
Ambiguous type! ]
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a | a -> flag where { ... }
instance Show a => PrintHelper T1 a
instance PrintHelper T2 a
instance PrintHelper flag a => Print a where { ... }
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a | a -> flag where { ... }
-- vvvv --
instance Show a => PrintHelper T1 a
instance PrintHelper T2 a
-- ^^^^ --
instance PrintHelper flag a => Print a where { ... }
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a | a -> flag where { ... }
instance PrintHelper T1 Int
instance PrintHelper T1 String
-- ...
instance Show a => PrintHelper T1 [a]
-- ...
instance PrintHelper T2 a
instance PrintHelper flag a => Print a where { ... }
]
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a | a -> flag where { ... }
instance PrintHelper T1 Int
instance PrintHelper T1 String
-- ...
instance Show a => PrintHelper T1 [a]
-- ...
instance (T2 ~ f) => PrintHelper f a
instance PrintHelper flag a => Print a where { ... }
layout: false .left-column[
] .right-column[
- Add an extra parameter!
data T1
data T2
class PrintHelper flag a | a -> flag where { ... }
instance PrintHelper T1 Int
instance PrintHelper T1 String
-- ...
instance Show a => PrintHelper T1 [a]
-- ...
instance (T2 ~ f) => PrintHelper f a
instance PrintHelper flag a => Print a where { ... }
[1 of 1] Compiling Main ( ex3.hs, interpreted )
Ok, modules loaded: Main.
layout: false .left-column[
] .right-column[
{-# LANGUAGE FlexibleInstances,
UndecidableInstances,
TypeFamilies,
OverlappingInstances,
FunctionalDependencies #-}
data T1
data T2
class Print a where
print :: a -> String
class PrintHelper flag a | a -> flag where
ph :: a -> String
instance PrintHelper T1 Int where ph = show
instance PrintHelper T1 String where ph = show
-- ...
instance Show a => PrintHelper T1 [a] where ph = show
-- ...
instance (T2 ~ f) => PrintHelper f a where
ph = const "no show"
instance PrintHelper flag a => Print a where
print = ph
layout: false .left-column[
] .right-column[
data TTrue
data TFalse
class ShowPred a flag | a -> flag
instance ShowPred Int TTrue
instance ShowPred Bool TTrue
-- ...
instance ShowPred a flag => ShowPred Bool flag
-- ...
instance (TFalse ~ a) => ShowPred a flag
layout: false .left-column[
] .right-column[
data TTrue
data TFalse
class ShowPred a flag | a -> flag
instance ShowPred Int TTrue
instance ShowPred Bool TTrue
-- ...
instance ShowPred a flag => ShowPred Bool flag
-- ...
instance (TFalse ~ a) => ShowPred a flag
class PrintHelper flag a where
ph :: flag -> a -> String
instance Show a => PrintHelper TTrue a where
ph _ = show
instance PrintHelper TFalse a where
ph _ = const "No show method"
instance (ShowPred a flag, PrintHelper flag a) => Print a where
print = ph (undefined::flag)
layout: false .left-column[
] .right-column[
data TTrue
data TFalse
class ShowPred a flag | a -> flag
instance ShowPred Int TTrue
instance ShowPred Bool TTrue
-- ...
instance ShowPred a flag => ShowPred Bool flag
-- ...
instance (TFalse ~ a) => ShowPred a flag
class PrintHelper flag a where
ph :: flag -> a -> String
-- ^^ --
instance Show a => PrintHelper TTrue a where
ph _ = show
instance PrintHelper TFalse a where
ph _ = const "No show method"
instance (ShowPred a flag, PrintHelper flag a) => Print a where
print = ph (undefined::flag)
-- ^^^^^ ---
]
layout: false .left-column[
] .right-column[
layout: false .left-column[
] .right-column[
data TShow
data TOrd
data TNone
class WhichClass a flag | a -> flag
instance WhichClass Int TOrd
instance WhichClass Bool TShow
-- ...
instance WhichClass a flag => WhichClass [a] flag
-- ...
instance (flag ~ TNone) => WhichClass a flag
class PrintHelper flag a where
ph :: flag -> a -> String
instance Show a => PrintHelper TShow a where
ph _ = show
instance Ord a => PrintHelper TOrd a where
ph _ = const "Is Ord"
instance PrintHelper TNone a where
ph _ = const "Not Show or Ord"
class Print a where
print :: a -> String
instance (WhichClass a flag, PrintHelper flag a) => Print a where
print = ph (undefined::flag)
layout: false .left-column[
] .right-column[
data TShow
data TOrd
data TNone
class WhichClass a flag | a -> flag
instance WhichClass Int TOrd -- < Explict order
instance WhichClass Bool TShow
-- ...
instance WhichClass a flag => WhichClass [a] flag
-- ...
instance (flag ~ TNone) => WhichClass a flag
class PrintHelper flag a where
ph :: flag -> a -> String
instance Show a => PrintHelper TShow a where
ph _ = show
instance Ord a => PrintHelper TOrd a where
ph _ = const "Is Ord"
instance PrintHelper TNone a where
ph _ = const "Not Show or Ord"
class Print a where
print :: a -> String
instance (WhichClass a flag, PrintHelper flag a) => Print a where
print = ph (undefined::flag)
]