Haskell: ссылка на тип значения во время компиляции

Мне интересно, есть ли хороший способ ссылаться на типы значений без явного наложения их с помощью type в коде (не во время выполнения - здесь не происходит reification).

Возьмите следующий код (используя Data.Vinyl):

{-# LANGUAGE DataKinds, TypeOperators #-}

import Data.Vinyl

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

Здесь у нас есть типы "name" ::: String а также "age" ::: Int повторяется в двух местах. Если мы повторно используем поля в нескольких записях, это может стать несколькими местами. Несмотря на то, что Person Тип действительно ссылается на составляющие поля, объявления типов являются независимыми. Так меняется age быть представленным FloatСкажем, требует перемен в разных местах.

Очевидно, что нет необходимости явно набирать вещи, так как они будут выведены. Однако в моем случае типы записей возвращаются из анализатора параметров и, следовательно, экспортируются. Точно так же можно написать следующее:

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

Однако это тогда включает другую загрузку псевдонимов типов и удваивает число строк. Я хотел бы написать следующее:

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

Это явно связывает тип Person к типам его полей.

Есть ли способ (желательно sans-TH, но мне было бы интересно даже задействовать TH) сделать это?

1 ответ

Решение

Это должно быть достаточно легко сделать String -> [Name] -> DecsQ функционировать из следующего. Жаль, что с ghc7.6 (по крайней мере) проверка циклов в синонимах типов, кажется, останавливает красивее type Person = $(listOfT ['name, 'age]) от разработки.

{-# 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])
Другие вопросы по тегам