[英]Haskell - Using one data type kind in another
Haskell新手; 我希望能夠聲明Val
,它可以是IntVal, StringVal FloatVal
,也可以是一個List
,可以是StringList, IntList, FloatList
,其元素是(相應地): StringVal, IntVal and FloatVal
。 到目前為止我的嘗試:
data Val = IntVal Int
| FloatVal Float
| StringVal String deriving Show
data List = IntList [(IntVal Int)]
| FloatList [(FloatVal Float)]
| StringList [(StringVal String)] deriving Show
失敗並顯示以下錯誤:
Not in scope: type constructor or class ‘IntVal’
A data constructor of that name is in scope; did you mean DataKinds?
data List = IntList [(IntVal Int)]
... (similarly for StringVal, FloatVal..)
什么是實現此目標的正確方法?
PS:將列表聲明為data List = List [Val]
最終允許List如下:l = [(IntVal 10),(StringVal“ Hello”)],我不想允許。
我希望列表的每個元素都是相同的Value
有使用GADT的解決方案。 問題在於IntVal
等實際上不是類型,它們只是單個類型Val
構造函數(基本上也支持模式匹配的函數)。 因此,一旦創建了Val
,有關類型的值的信息就會在類型級別(即編譯時)完全丟失。
訣竅是用Val
包含的類型標記Val
。
data Val a where
IntVal :: Int -> Val Int
FloatVal :: Float -> Val Float
StringVal :: String -> Val String
然后,如果您有一個簡單列表[Val a]
,它將已經是同質的。 如果你必須:
data List = IntList [Val Int]
| FloatList [Val Float]
...
這與“擦除”列表的類型略有不同,例如,它可以區分空白的int列表和空白的floats列表。 您也可以對List使用相同的GADT技巧
data List a where
IntList :: [Val Int] -> List Int
FloatList :: [Val Float] -> List Float
...
但在那種情況下,我認為更好的設計可能更簡單
newtype List a = List [Val a]
所有這些不同設計之間的權衡實際上取決於您打算如何處理它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.