Simon Peyton-Jones wrote:
can you tell us about the most persuasive, fun application
you've encountered, for type families or functional dependencies?
I'm using them to provide witnesses to lenses.
Given two lenses on the same base type, I want to compare them, and if
they're the same lens, know that they have the same view type.
data Lens base view = MkLens
{
-- lensWitness :: ???,
lensGet :: base - view,
lensPut :: base - view - base
};
How do I compare Lens base view1 and Lens base view2, and match up
view1 and view2?
The difficulty is that my witnesses are monomorphic, while a lens may be
polymorphic. For instance, the lens corresponding to the fst function:
fstLens :: Lens (a,b) a;
fstLens = MkLens
{
lensGet = fst,
lensPut = \(_,b) a - (a,b)
};
I only want to generate one open witness for fstLens, but what is its type?
This is where type functions come in. I have a type family TF, and a
basic set of instances:
type family TF tf x;
data TFIdentity;
type instance TF TFIdentity x = x;
data TFConst a;
type instance TF (TFConst a) x = a;
data TFApply (f :: * - *);
type instance TF (TFApply f) x = f x;
data TFMatch;
type instance TF TFMatch (f a) = a;
data TFMatch1;
type instance TF TFMatch1 (f a b) = a;
data TFCompose tf1 tf2;
type instance TF (TFCompose tf1 tf2) x = TF tf1 (TF tf2 x);
I create a new witness type, that witnesses type functions:
import Data.Witness;
data TFWitness w x y where
{
MkTFWitness :: w tf - TFWitness w x (TF tf x);
};
instance (SimpleWitness w) = SimpleWitness (TFWitness w x) where
{
matchWitness (MkTFWitness wtf1) (MkTFWitness wtf2) = do
{
MkEqualType - matchWitness wtf1 wtf2;
return MkEqualType;
};
};
So for my lens type, I want a witness for the type function from base to
view:
data Lens base view = MkLens
{
lensWitness :: TFWitness IOWitness base view,
lensGet :: base - view,
lensPut :: base - view - base
};
For our fst lens, I can now generate a witness for the function from
(a,b) to a.
fstWitness :: IOWitness TFMatch1;
fstWitness - newIOWitness; -- language extension
fstLens :: Lens (a,b) a;
fstLens = MkLens
{
lensWitness = MkTFWitness fstWitness,
lensGet = fst,
lensPut = \(_,b) a - (a,b)
};
I can now compare two lenses like this:
get1put2 :: Lens base view1 - Lens base view2 - base - Maybe base;
get1put2 lens1 lens2 b = do
{
MkEqualType - matchWitness (lensWitness lens1) (lensWitness lens2);
return (lensPut lens2 b (lensGet lens1 b));
};
(Actually, I'm doing something a bit more useful than get1put2.)
--
Ashley Yakeley
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe