[Haskell-cafe] An issue with EDSLs in the ``finally tagless'' tradition

Brad Larsen brad.larsen at gmail.com
Fri Sep 25 00:17:08 EDT 2009


Wren,

On Thu, Sep 24, 2009 at 8:36 PM, wren ng thornton <wren at freegeek.org> wrote:
> Brad Larsen wrote:
>>
>> The modularity problem I speak of is that to add a new interpretation of
>> the
>> DSL, I will likely have to modify the EDSL definition to add additional
>> constraints.  Ideally, I would like to be able to define the EDSL once, in
>> a
>> module, and be able to write arbitrary interpretations of it in other
>> modules, without having to go back and change the EDSL definition.
>
> The canonical, if theoretically unsatisfying, way to do this is to lift all
> type variables into the class specification. Thus, instead of
>
>    class Foo f where
>        foo :: forall a. a -> f a
>
> we would instead have
>
>    class Foo f a where
>        foo :: a -> f a
>
> According to the intention of the design, variables thus lifted should
> remain polymorphic in instances however they can have contexts applied to
> them:
>
>    instance (Num a) => Foo F a where
>        foo = ...
>
> The reason this is unsatisfying is that there's no way to enforce that
> instances don't ground these variables, which can interfere with the
> validity of applying certain laws/transformations. Also, if you need to lift
> more than one variable in the same class then it can be tricky to do the
> encoding right. For instance, when converting Monad into this form (e.g. so
> we can define an instance for Set) it is prudent to separate it into one
> class for return and another for join/(>>=)/(>>). But it does solve the
> problem at hand.
>
> --
> Live well,
> ~wren
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>

I have experimented some in the past day with this canonical technique
of lifting type variables into the class specification.  This is
somewhat successful; however, one problem is that when multiple
variables are lifted into the specification, ambiguity creeps in (and
over-generality?), in the absence of superclass constraints or
functional dependencies.

So, for example, Foo seems to work well, but Bar does not:

    class Foo a where
        ...

    class Bar a b where
        ...

One can alleviate the ambiguity of Bar by splitting it into two
classes, similarly to splitting up Monad:

    class PreBar a where
        ...

    class (PreBar a) => Bar a b where
        ...

It's not clear to me that such a decomposition is always possible.
I'll keep experimenting with modular, tagless EDSLs...

Sincerely,
Brad


More information about the Haskell-Cafe mailing list