[Haskell-cafe] translating bidirectional fundeps to TFs

Gábor Lehel illissius at gmail.com
Sat Sep 18 08:27:45 EDT 2010

On Fri, Sep 17, 2010 at 10:19 PM, Dan Doel <dan.doel at gmail.com> wrote:
> On Friday 17 September 2010 4:04:26 pm Gábor Lehel wrote:
>> What I would *want* to write is this:
>> class (Mutable (Thawed a), Frozen (Thawed a) ~ a) => Immutable a where
>>     type Thawed a :: *
>>     thaw :: a -> Thawed a
>> class (Immutable (Frozen a), Thawed (Frozen a) ~ a) => Mutable a where
>>     type Frozen a :: *
>>     freeze :: a -> Frozen a
>> This looks considerably nicer, but it's not valid -- I get a cycle in
>> class declarations via superclasses error, on the one hand, and (if I
>> remove that) an infinite loop in the typechecker (context reduction
>> stack overflow) on the other (FlexibleContexts being a prerequisite
>> for most of the interesting things you can do with TypeFamilies).
>> So what should one, theoretically, do here? Is there a way to express
>> this using TypeFamilies which preserves both the semantics and the
>> symmetry of the FDs version, and is also valid? Or should one just go
>> ahead and use the FDs because, in this case, they're simply better
>> suited? *Or* should one just suck it up and go with the ugly
>> TypeFamilies version because TypeFamilies are The Future*?
> What about:
>  class (Thawed frozen ~ thawed, Frozen thawed ~ frozen)
>        => TwoPhase thawed frozen where
>    type Thawed frozen :: *
>    type Frozen thawed :: *
>    thaw   :: frozen -> thawed
>    freeze :: thawed -> frozen
> This is the translation I'd expect for the fundep. And ideally, in the future,
> you could use the original class with fundeps as sugar for the above, because
> fundeps are a nice way of expressing mutual dependency like this (just as
> associated types are nicer than making the associated type a class parameter
> as is required by fundeps).

Hmm. I had a similar thought, but dismissed it because I was under the
impression that you needed to use all the parameters of the class as
parameters of its associated types. But apparently that was mistaken
-- or, at least, your example compiles. :)

The redundancy is sort of annoying ('thawed' and 'Thawed frozen' both
being necessary and necessarily equivalent). This is a case where
associated type defaults would be helpful, to eliminate at least some
of it (namely, having to define Thawed and Frozen in every instance,
even though only one definition is possible). Anyway, it's a shame you
can't really decouple the two halves as in my nonworking example, but
this is nicer than the other alternative I had. Thanks!

> -- Dan
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe

Work is punishment for failing to procrastinate effectively.

More information about the Haskell-Cafe mailing list