generic function extension in haskell
DESCRIPTION
Generic function extension in Haskell. Ralf L ä mmel, Vrije University Simon Peyton Jones, Microsoft Research. What’s function extension?. You have A generic query gen :: Data a => a -> R A type-specific query spec :: T -> R - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/1.jpg)
Generic function extension Generic function extension in Haskellin Haskell
Ralf LRalf Läämmel, Vrije Universitymmel, Vrije University
Simon Peyton Jones, Microsoft ResearchSimon Peyton Jones, Microsoft Research
![Page 2: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/2.jpg)
What’s function extension?What’s function extension?
You have You have A generic query A generic query gen :: Data a => a -> Rgen :: Data a => a -> R
A type-specific queryA type-specific queryspec :: T -> Rspec :: T -> R
You want a generic function which You want a generic function which behaves like behaves like specspec on values of type T, on values of type T, and like and like gengen on all other values on all other valuesgen `extQ` spec :: Data a => a -> Rgen `extQ` spec :: Data a => a -> R
![Page 3: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/3.jpg)
ExampleExamplegshow, gshow’ :: Data a => a -> String
gshow = gshow’ `extQ` showString
showString :: String -> String
showString s= “\”” ++ s ++ “\””
gshow’ x = “(“ ++ show (toConstr x)
++ concat (gmapQ gshow x)
++ “)”
-- gmapQ :: Data a
-- => (forall b. Data b => b->r)
-- -> a -> [r]
![Page 4: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/4.jpg)
Defining extQDefining extQextQ :: (Typeable a, Typeable b)
=> (a->r) -> (b->r) -> a -> r
extQ gen spec x
= case (cast x) ofJust x’ -> spec x’Nothing -> gen x
cast :: (Typeable a, Typeable b)
=> a -> Maybe b
![Page 5: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/5.jpg)
Type safe castType safe cast
cast :: (Typeable a, Typeable b)
=> a -> Maybe b
ghci> (cast 'a') :: Maybe Char
Just 'a'
ghci> (cast 'a') :: Maybe Bool
Nothing
ghci> (cast True) :: Maybe Bool
Just True
![Page 6: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/6.jpg)
Implementing castImplementing castdata TypeRep
instance Eq TypeRep
mkRep :: String -> [TypeRep] -> TypeRep
class Typeable a where
typeOf :: a -> TypeRep
instance Typeable Int where
typeOf i = mkRep "Int" []
Guaranteed not to evaluate its
argument
An Int, perhaps
![Page 7: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/7.jpg)
Implementing castImplementing castclass Typeable a where
typeOf :: a -> TypeRep
instance (Typeable a, Typeable b) => Typeable (a,b) where
typeOf p = mkTyConApp(mkTyCon "(,)")[ta,tb]
where
ta = typeOf (fst p)tb = typeOf (snd p)
![Page 8: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/8.jpg)
Implementing castImplementing cast
cast :: (Typeable a, Typeable b)
=> a -> Maybe b
cast x = r
where
r = if typeOf x == typeOf (get r)
then Just (unsafeCoerce x)
else Nothing
get :: Maybe a -> a
get x = undefined
![Page 9: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/9.jpg)
Implementing castImplementing cast
In GHC: In GHC: Typeable instances are generated Typeable instances are generated
automatically by the compiler for any data automatically by the compiler for any data typetype
The definition of cast is in a libraryThe definition of cast is in a library
Then cast is soundThen cast is sound
Bottom line: cast is best thought of as a Bottom line: cast is best thought of as a language extension, but it is an easy one language extension, but it is an easy one to implement. All the hard work is done to implement. All the hard work is done by type classesby type classes
![Page 10: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/10.jpg)
Generalisation 1Generalisation 1Leibnitz equalityLeibnitz equality
![Page 11: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/11.jpg)
Back to function extensionBack to function extension
You have You have A generic A generic transformtransform gen :: Data a => a -> agen :: Data a => a -> a
A type-specific transformA type-specific transformspec :: T -> Tspec :: T -> T
You want a generic function which You want a generic function which behaves like behaves like specspec on values of type T, on values of type T, and like and like gengen on all other values on all other valuesgen `extT` spec :: Data a => a -> agen `extT` spec :: Data a => a -> a
![Page 12: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/12.jpg)
Defining extTDefining extTextT :: (Typeable a, Typeable b)
=> (a->a) -> (b->b) -> a -> a
extT gen spec x
= case (cast x) ofJust x’ -> spec xNothing -> gen x
Wrong result type!
![Page 13: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/13.jpg)
Defining extTDefining extT
extT :: (Typeable a, Typeable b)
=> (a->a) -> (b->b) -> a -> a
extT gen spec x
= case (cast spec) ofJust spec’ -> spec’ xNothing -> gen x
Instead, cast spec
Compares type rep for (a->a) with that ofr (b->b), when all that is necessary is to compare a and b.
![Page 14: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/14.jpg)
What about extM?What about extM?extM :: (Typeable a, Typeable b)
=> (a->m a)-> (b->m b)-> a -> m a
Need to compare type rep for (a->m a) with that for (b->m b), so we actually need.
extM :: (Typeable a, Typeable b,
Typeable (m a), Typeable (m b))
=> (a->m a)-> (b->m b)-> a -> m a
Sigh: complex, and adds bogus constraints
![Page 15: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/15.jpg)
Use Leibnitz equality!Use Leibnitz equality!
Abstracts over arbitrary type constructor cAbstracts over arbitrary type constructor c
Now extM is simple...Now extM is simple...
gcast :: (Typeable a, Typeable b)
=> c a -> Maybe (c b)
![Page 16: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/16.jpg)
Defining extMDefining extMnewtype M m a = M (a -> m a)
extM :: (Typeable a, Typeable b)
=> (a->m a)-> (b->m b)-> a -> m a
extM gen spec x
= case gcast (M spec) of
Just (M spec’) -> spec’ x
Nothing -> gen x
No problem with the ‘m’ partNo problem with the ‘m’ part
Compares type reps only for a, b.Compares type reps only for a, b.
![Page 17: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/17.jpg)
Generalisation 2Generalisation 2polymorphic function polymorphic function
extensionextension
![Page 18: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/18.jpg)
Polymorphic function extensionPolymorphic function extension
So far we have only monomorphic function So far we have only monomorphic function extension. Given extension. Given
show :: Data a => a -> Stringshow :: Data a => a -> Stringwe can extend it with a type-specific functionwe can extend it with a type-specific function
showInt :: Int -> StringshowInt :: Int -> Stringoror showFoogle :: Tree [Int] -> StringshowFoogle :: Tree [Int] -> String
But we But we can’tcan’t extend it with a polymorphic extend it with a polymorphic function:function:
showList :: Data a => [a] -> StringshowList :: Data a => [a] -> String
![Page 19: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/19.jpg)
WantedWantedextQ1 :: (Data a, Typeable1 t)
=> (a -> r)
-> (forall b. Data b => t b -> r)
-> (a -> r)
compare previous:
extQ :: (Typeable a, Typeable b)
=> (a -> r)
-> (b -> r)
-> (a -> r)
![Page 20: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/20.jpg)
Then we could do:Then we could do:gshow, gshow’ :: Data a => a -> String
gshow = gshow’ `extQ` showString
`extQ1` showList
showString :: String -> String
showString s= “\”” ++ s ++ “\””
showList :: Data a => [a] -> String
showList xs = “[“
++ intersperse “,” (map gshow xs)
++ “]”
gshow’ x = ...unchanged...
![Page 21: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/21.jpg)
Digression 1Digression 1What is Typeable1?What is Typeable1?
![Page 22: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/22.jpg)
TypeableTypeable
class Typeable a where
typeOf :: a -> TypeRep
instance Typeable a => Typeable [a] where
typeOf _ = mkTyConApp (mkTyCon “[]”)(typeOf (undefined::a))
a :: *
Proxy type argument
![Page 23: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/23.jpg)
Typeable1Typeable1
class Typeable1 t where
typeOf :: t a -> TypeRep
instance Typeable1 [] where
typeOf _ = mkTyConApp (mkTyCon “[]”) []
t::*->*
But what about Typeable [a]?But what about Typeable [a]?
![Page 24: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/24.jpg)
Typeable1Typeable1
class Typeable1 t where
typeOf1 :: t a -> TypeRep
instance Typeable1 [] where
typeOf1 _ = mkTyConApp (mkTyCon “[]”) []
instance (Typeable1 t, Typeable a)
=> Typeable (t a) where
typeOf _ = mkAppTy
(typeOf1 (undefined::t a))
(typeOf (undefined::a))
t::*->*
![Page 25: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/25.jpg)
SighSigh
Typeable2 (t :: *->*->*)Typeable2 (t :: *->*->*)
Typeable3 (t :: *->*->*->*)Typeable3 (t :: *->*->*->*)
...how far?...how far?
and what aboutand what aboutTypeable1_2 (t :: (*->*) -> *)Typeable1_2 (t :: (*->*) -> *)
etcetc
![Page 26: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/26.jpg)
Wanted: kind polymorphismWanted: kind polymorphism
No! Only works if k = *No! Only works if k = *
class Typeable (a::k) where
typeOf :: a -> TypeRep
![Page 27: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/27.jpg)
Wanted: kind polymorphismWanted: kind polymorphismclass Typeable (a::k) where
typeOf :: Proxy a -> TypeRep
-- typeOf :: forall k. forall a:k.
-- Proxy a -> TypeRep
data Proxy (a::k)
-- Proxy :: forall k. k -> *
![Page 28: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/28.jpg)
Wanted: kind polymorphismWanted: kind polymorphismclass Typeable (a::k) where
typeOf :: Proxy a -> TypeRep
instance Typeable [] where
typeOf _ = mkTyConApp (mkTyCon “[]”) []
instance (Typeable t, Typeable a)
=> Typeable (t a) where
typeOf _ = mkAppTy
(typeOf (undefined::Proxy t))
(typeOf (undefined::Proxy a))
![Page 29: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/29.jpg)
End of digression 1End of digression 1
![Page 30: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/30.jpg)
Back to extQ1Back to extQ1extQ1 :: (Data a, Typeable1 t)
=> (a -> r)
-> (forall b. Data b => t b -> r)
-> (a -> r)
compare previous:
extQ :: (Typeable a, Typeable b)
=> (a -> r)
-> (b -> r)
-> (a -> r)
![Page 31: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/31.jpg)
Recall extQ implementationRecall extQ implementation
compare previous
extQ :: (Typeable a, Typeable b)
=> (a->r) -> (b->r) -> a -> r
extQ gen spec x
= case gcast (Q spec) ofJust (Q spec’) -> spec’ x’Nothing -> gen x
newtype Q r a = Q (a->r)
gcast :: (Typeable a, Typeable b)
=> c a -> Maybe (c b)
![Page 32: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/32.jpg)
Implementation of extQ1Implementation of extQ1extQ1 :: (Data a, Typeable1 t)
=> (a->r)-> (forall b.Data b => t b -> r)
-> (a->r)
extQ1 gen spec x
= case dataCast1 (Q spec) of
Just (Q spec’) -> spec’ x
Nothing -> gen x
newtype Q r a = Q (a->r)
dataCast1 :: (Data a, Typeable1 t)
=> (forall b. Data b => c (t b))
-> Maybe (c a)
![Page 33: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/33.jpg)
Implementation of extQ1Implementation of extQ1extQ1 :: (Data a, Typeable1 t)
=> (a->r)-> (forall b.Data b => t b -> r)
-> (a->r)
extQ1 gen spec x
= case dataCast1 (Q spec) of
Just (Q spec’) -> spec’ x
Nothing -> gen x
newtype Q r a = Q (a->r)
dataCast1 :: (Data a, Typeable1 t)
=> (forall b. Data b => c (t b))
-> Maybe (c a)
The $64M question:How does dataCast1
get the (Data b) dictionary to pass to
spec?
![Page 34: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/34.jpg)
The stunning blow!The stunning blow!
Answer: dataCast1 is a method of DataAnswer: dataCast1 is a method of Data
class Typeable a => Data a where
...
dataCast1 :: Typeable1 t
=> forall b. Data b => c (t b))
-> Maybe (c a)
![Page 35: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/35.jpg)
Instances are trivialInstances are trivialinstance Data a => Data [a] where
...
dataCast1 f = gcast1 f
gcast1 :: (Typeable1 t, Typeable1 s)
=> c (t a)
-> Maybe (c (s a))
![Page 36: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/36.jpg)
Instances are trivialInstances are trivialinstance (da:Data a) => Data [a] where
...
dataCast1 (tt:Typeable1 t) f
= gcast1 (tt,tList) (f da)
tList :: Typeable1 List
gcast1 :: (Typeable1 t, Typeable1 s)
=> c (t a)
-> Maybe (c (s a))
![Page 37: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/37.jpg)
Gcast1 is just like castGcast1 is just like cast
gcast1 :: (Typeable1 t, Typeable1 s)
=> c (t a)
-> Maybe (c (s a))
gcast1 (x::c (t a)) :: Maybe (c (s a)
= if typeOf1 (undefined::t a)
== typeOf1 (undefined::s a)
then Just (unsafeCoerce x)
else Nothing
![Page 38: Generic function extension in Haskell](https://reader031.vdocument.in/reader031/viewer/2022020111/56814cf9550346895dba0f07/html5/thumbnails/38.jpg)
ConclusionsConclusionsPolymorphic type extension is Polymorphic type extension is (surprisingly) possible(surprisingly) possible
We want polymorphism at the kind level. We want polymorphism at the kind level. Are there other applications for this? How Are there other applications for this? How much more complicated does the type much more complicated does the type system become?system become?
Papers: http://research.microsoft.com/~simonpj