2014-01-29 12 views
6

Ich frage mich, ob es eine schöne Möglichkeit gibt, auf Typen von Werten zu verweisen, ohne sie explizit mit type im Code zu aliasieren (nicht zur Laufzeit - hier findet keine Verdinglichung statt).Haskell: beziehen sich auf den Werttyp zur Kompilierzeit

Nehmen Sie den folgenden Code (mit):

{-# LANGUAGE DataKinds, TypeOperators #-} 

import Data.Vinyl 

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

Hier haben wir die Typen "name" ::: String und "age" ::: Int an zwei Stellen wiederholt. Wenn wir Felder in mehreren Datensätzen wiederverwenden, kann dies zu mehreren Orten werden. Trotz der Tatsache, dass der Person Typ ist wirklich Verweisung auf die konstituierenden Felder, sind die Typdeklarationen unabhängig. So ändert sich age, um durch Float dargestellt werden, erfordert Änderungen an verschiedenen Orten.

Offensichtlich ist es nicht notwendig, Dinge explizit einzugeben, da sie abgeleitet werden. In meinem Fall werden die Datensatztypen jedoch von einem Optionsparser zurückgegeben und somit exportiert. Ebenso könnte man folgendes schreiben:

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

Dies bedingt jedoch dann eine weitere Ladung von Typ-Aliasnamen und die doppelte Anzahl von Linien. Was würde ich wieder Lage sein, zu schreiben, ist die folgende:

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

Dies verbindet explizit den Typ eines Person auf die Arten der Felder.

Gibt es einen Weg (vorzugsweise Sans-TH, aber ich wäre daran interessiert, sogar TH), dies zu tun?

+4

Um ehrlich zu sein, bevorzuge ich die erste Version mit den Aliasen zu der zweiten mit der Typeof. Sie haben sogar eine ordentliche Benennungskonvention bereits (Felder in Kleinbuchstaben und Typen in Großbuchstaben) – hugomg

+1

Was ist los mit Vorlage Haskell? Das ist ein guter Weg, um Ihr Problem zu lösen. Ich kenne die Vinyl-Ansicht der Welt nicht, aber "Objektiv" -Simen: https://github.com/ekmett/lens/wiki/Examples – misterbee

Antwort

0

Es sollte einfach genug sein, um eine String -> [Name] -> DecsQ Funktion aus folgende zu machen. Schade mit ghc7.6 (zumindest), die Überprüfung für Zyklen in Typ Synonyme scheint zu stoppen die schönere type Person = $(listOfT ['name, 'age]) von Ausarbeitung.

{-# 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]) 
Verwandte Themen