[Haskell-cafe] reifying typeclasses
Emil Axelsson
emax at chalmers.se
Mon Sep 16 09:31:22 CEST 2013
2013-09-15 11:16, oleg at okmij.org skrev:
> Evan Laforge wrote:
>> I have a typeclass which is instantiated across a closed set of 3
>> types. It has an ad-hoc set of methods, and I'm not too happy with
>> them because being a typeclass forces them to all be defined in one
>> place, breaking modularity. A sum type, of course, wouldn't have that
>> problem. But in other places I want the type-safety that separate
>> types provide, and packing everything into a sum type would destroy
>> that. So, expression problem-like, I guess.
>>
>> It seems to me like I should be able to replace a typeclass with
>> arbitrary methods with just two, to reify the type and back. This
>> seems to work when the typeclass dispatches on an argument, but not on
>> a return value. E.g.:
>
> If the universe (the set of types of interest to instantiate the type
> class to) is closed, GADTs spring to mind immediately. See, for
> example, the enclosed code. It is totally unproblematic (one should
> remember to always write type signatures when programming with
> GADTs. Weird error messages otherwise ensue.)
>
> One of the most notable differences between GADT and type-class--based
> programming is that GADTs are closed and type classes are open (that
> is, new instances can be added at will). In fact, a less popular
> technique of implementing type classes (which has been used in some Haskell
> systems -- but not GHC)) is intensional type analysis, or typecase.
> It is quite similar to the GADT solution.
I've been toying with using Data Types à la Carte to get type
representations, a `Typeable` class and dynamic types parameterized by a
possibly open universe:
https://github.com/emilaxelsson/dsl-factory/blob/master/TypeReify.hs
Using this module (which depends on the syntactic package), Evan's
problem can be solved easily without setting up any new classes or data
types, as shown below.
/ Emil
import Language.Syntactic
import TypeReify
type Universe = IntType :+: CharType
argument :: forall a . Typeable Universe a => a -> Int
argument a
| Just IntType <- prj t = a
| Just CharType <- prj t = fromEnum a
-- Note: All cases are covered, since `Universe` is closed
where
TypeRep t = typeRep :: TypeRep Universe a
result :: forall a . Typeable Universe a => Int -> a
result a
| Just IntType <- prj t = a
| Just CharType <- prj t = toEnum a
-- Note: All cases are covered, since `Universe` is closed
where
TypeRep t = typeRep :: TypeRep Universe a
-- Note that we do not have to use a closed universe. Here's an alternative,
-- open version of `argument`:
argument' :: forall u a . (IntType :<: u, CharType :<: u) =>
Typeable u a => a -> Int
argument' a
| Just IntType <- prj t = a
| Just CharType <- prj t = fromEnum a
| otherwise = 0 -- or whatever :)
where
TypeRep t = typeRep :: TypeRep u a
More information about the Haskell-Cafe
mailing list