Skip to content

Instantly share code, notes, and snippets.

@jkarni
Last active August 29, 2015 14:05
Show Gist options
  • Save jkarni/eee354172f854959f902 to your computer and use it in GitHub Desktop.
Save jkarni/eee354172f854959f902 to your computer and use it in GitHub Desktop.
Polycephaly presentation source.

name: inverse layout: true class: center, middle, inverse

#Polycephaly Or, multiplying instance heads


The Problem


layout: false .left-column[

The Problem

] .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[

The Problem

] .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[

The Problem

] .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

Instance heads cannot match. ]

layout: false .left-column[

The Problem

] .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[

The Problem

] .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[

The Problem

] .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[

The Problem

] .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 {...}

] searchpath

layout: false .left-column[

The Problem

] .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[

The Problem

] .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[

The Problem

] .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[

The Problem

] .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: ]

layout: false .left-column[

The Problem

] .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[

The Problem

] .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[

The Problem

] .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!

]

name: inverse layout: true class: center, middle, inverse

The Solution


layout: false .left-column[

The Solution

] .right-column[ ]

layout: false .left-column[

The Solution

] .right-column[

  • Add an extra parameter! ]

layout: false .left-column[

The Solution

] .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[

The Solution

] .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[

The Solution

] .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[

The Solution

] .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[

The Solution

] .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 { ... }

Functional dependency conflict! ]

layout: false .left-column[

The Solution

] .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[

The Solution

] .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[

The Solution

] .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 { ... }

It compiles!

[1 of 1] Compiling Main             ( ex3.hs, interpreted )
Ok, modules loaded: Main.

]

layout: false .left-column[

The Solution

] .right-column[

Runnable Code

{-# 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[

The Solution

] .right-column[

The Show Predicate

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[

The Solution

] .right-column[

The Show Predicate

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[

The Solution

] .right-column[

The Show Predicate

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[

The Solution

] .right-column[

Three Heads

]

layout: false .left-column[

The Solution

] .right-column[

Three Heads

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[

The Solution

] .right-column[

Three Heads

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)

]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment