Question

I'm wondering if there's a nice way to refer to types of values without explicitly aliasing them using type in code (not at runtime - there is no reification going on here).

Take the following code (using Data.Vinyl):

{-# LANGUAGE DataKinds, TypeOperators #-}

import Data.Vinyl

name = Field :: "name" ::: String
age = Field :: "age" ::: Int
type Person = ["name" ::: String, "age" ::: Int]

Here we have the types "name" ::: String and "age" ::: Int repeated in two places. If we reuse fields in multiple records, this can become multiple places. Despite the fact that the Person type is really referring to the constituent fields, the type declarations are independent. So changing age to be represented by Float, say, requires changes in various places.

Obviously it's not necessary to explicitly type things, since they will be inferred. However, in my case the record types are being returned from an options parser, and thus exported. Likewise, one could write the following:

type Name = "name" ::: String
name = Field :: Name
type Age = "age" ::: Int
age = Field :: Age
type Person = [Name, Age]

However, this then involves another load of type aliases and double the number of lines. What I would like to be able to write is the following:

name = Field :: "name" ::: String
age = Field :: "age" ::: Int
type Person = [typeof name, typeof age]

This explicitly links the type of a Person to the types of its fields.

Is there a way (preferably sans-TH, but I'd be interested even involving TH) to do this?

Was it helpful?

Solution

It should be easy enough to make a String -> [Name] -> DecsQ function out of the following. Too bad with ghc7.6 (at least), the check for cycles in type synonyms seems to stop the prettier type Person = $(listOfT ['name, 'age]) from working out.

{-# LANGUAGE DataKinds, TemplateHaskell, TypeOperators #-}
import Language.Haskell.TH
import Control.Applicative
import Data.Vinyl

name = Field :: "name" ::: String
age = Field :: "age" ::: Int

let listOfT (n:ns) = do
        VarI _ ty _ _ <- reify n
        (appT promotedConsT) (return ty) `appT` listOfT ns
    listOfT [] = promotedNilT
 in return <$> tySynD (mkName "Person") [] (listOfT ['name, 'age])
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top