[Template-haskell] splicing types

Alfonso Acosta alfonso.acosta at gmail.com
Wed Jul 2 12:37:35 EDT 2008


I think that the type-level library:
http://hackage.haskell.org/cgi-bin/hackage-scripts/package/type-level

It allows  to encode and make computations over numbers in the
type-level. For example, decimal number 100 is encoded as:

D1 :* D0 :* D0

For syntactic convenience, there's a module containing aliases (i.e.
type synonyms) with which you can write D100 instead of D1 :* D0 :*
D0.

In case the number you want to encode is out of the aliases range, you
can always encode it by hand (i.e. D1 :* D0 :* D0) or splice it with
dec2TypeLevel (http://hackage.haskell.org/packages/archive/type-level/0.2/doc/html/Data-TypeLevel-Num-Aliases-TH.html#v%3Adec2TypeLevel
)

I hope that helps. If you have any questions about the library or need
a new feature, please let me know.

On Mon, Jun 30, 2008 at 10:14 PM, Robert Greayer <robgreayer at yahoo.com> wrote:
> Hi,
>
> I've been using TH to implement a library that generates code in a 'foreign' language that corresponds to a haskell ADT, as well as the haskell & foreign code required to transmit (i.e. serialize and deserialize) values back and forth between a haskell program and the foreign program. I've run into some situations in which it would be useful for there to be a way to control the code generation declaratively by providing additional meta-data to the code generator, beyond just the ADT(s) themselves.  For example, suppose in a group of ADTs, certain fields should be omitted when serialized, and therefore not represented in the 'foreign' types, e.g.:
>
>> data Bar {
>>         val1 :: String,
>>         val2 :: Int -- omit this in serialization
>>     }
>
> As a 'first order' stab at handling this issue, I thought of using type aliases, e.g
>
>> type Omitted a = a
> ...
>>         val2 :: Omitted Int
>
> which could be generalized to a sort of 'annotation type', e.g.
>
>> type Ann a b = a
>> type Omitted = () -- a particular annotation
> ...
>>        val2 ::  Ann Int Omitted
>
> you could have multiple annotations, e.g.
>>        val2 :: Ann Int (Omitted,Ann1,Ann2) -- an Int with three annotations
>
> The code generator 'sees' the aliases, and can therefore act on the ones it understands.
>
> This works, but I immediately run into situations where more flexibility is needed.  Indeed, in the example I've chose ('omit'), all works ok when serializing the data, but what about *de* serializing (in haskell)?  Some value needs to be chosen for the omitted field.  An arbitrary default of (say) zero may not be appropriate.  What I'd really like to be able to do is parameterize my annotations with values.  'Omitted' would be parameterized with the default value to use, e.g.
>
>> type Omitted a = ()
> ...
>>        val2 :: Ann Int (Omitted 1000)
>
> But of course this doesn't work, as I'm dealing with types here, not expressions.  I could do something extremely hokey (hokier even than this system of annotations), like:
>
>> type I1000 = ()
> ...
>>        val2 :: Ann Int (Omitted I1000) -- read as 'omitted, with default of 1000'
>
> The code generator would determine the default value based on the name of the type 'Omitted' is applied to.  The user of the annotation system would have the ugly task of creating 'dummy' type aliases for any values that need passing (and it would be quite cumbersome to attempt a naming convention for strings, etc.)
>
> It's at this point that I had the (for me) clever idea of simply writing a 'type level encoder' for any haskell expression, and then splicing in the encoding at the appropriate point, e.g. my integer as a tuple-type of binary digits: (One,Zero,Zero,One) would be a type encoding of '9', given the existence of type (aliases) such as:
>
>> type One = ()
>> type Zero = ()
>
> A function to encode an integer into the TH.Syntax representation of such a tuple --
>
> (AppT (AppT (AppT (AppT (TupleT 4) (ConT ''One)) (ConT ''Zero)) (ConT ''Zero)) (ConT ''One))
>
> is fairly trivial, as is a function to decode it back into an integer.  It should (I think) be possible to write a pair of functions:
>
>> encT :: Q Exp -> Q Type
>> decT :: Q Type -> Q Exp
>
> to encode/decode arbitrary expressions into/from types.
>
> which would then allow my annotations to look like:
>
>>         val2 :: Ann Int (Omitted $(encT [|1000|]))
>
> and allow me to annotate types with just about anything else, as well, with the ugly details of encoding/decoding hidden from both the user of the annotation system, and any code generation system that makes use of annotations.  Which I found quite pleasing, since this 'quasi-annotations' feature is probably more powerful than some similar, 'intentional' annotation features of other languages, despite (afaik) not being an envisaged use of the language features involved.
>
> But then I tried it out and found that I'm trying to splice into what is currently an invalid splice position for TH.  (Indeed, on the very day that I decided to try my idea out concretely, the relevant ticket affecting type declarations as valid splice positions was downgraded to low priority, and disincluded from GHC 6.10 -- http://hackage.haskell.org/trac/ghc/ticket/1476).  So I was wondering if 1) splicing types is inseparable from the  (harder?) problem of splicing patterns and 2) if splicing types is something that will is likely at some point to be implemented (is it that a good solution isn't yet apparent, or that it's just not important enough for the goals of TH?) and 3) has this idea, or something similar, been explored (regardless of the fact that it won't work with TH as-implemented) before?
>
> Thanks,
> rcg
>
>
>
> _______________________________________________
> template-haskell mailing list
> template-haskell at haskell.org
> http://www.haskell.org/mailman/listinfo/template-haskell
>


More information about the template-haskell mailing list