2014-01-29 58 views
6

我想知道是否有一種很好的方法來引用值的類型,而不是在代碼中使用type(不是在運行時 - 這裏沒有實現)顯式地對它們進行別名。Haskell:參考編譯時的值類型

看看下面的代碼(使用):

{-# 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)來做到這一點?

+4

說實話,我更喜歡第一個版本的別名與第二個typeof。你甚至已經有了一個整潔的命名約定(字段以小寫字母和大寫字母表示) – hugomg

+1

模板Haskell有什麼問題?這是解決您的問題的好方法。我不知道世界的乙烯視圖,但'lens' sems適合:https://github.com/ekmett/lens/wiki/Examples – misterbee

回答

0

應該很容易使中的函數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])