我有下一个结构:
data BasicTypes = TypeS String
| TypeI Integer
deriving (Show, Ord, Eq)
data MRF = MRF {
lastValue :: BasicTypes,
requestedFilters :: [RF]
} deriving (Show)
data RF = RF {
event :: String,
filters :: [Filter]
} deriving (Show)
type BooleanFunction a = a -> Bool
data Filter = Filter {
operation :: BooleanFunction BasicTypes,
value :: BasicTypes
} deriving (Show)
我想要一个MRF数据,其中包含requestedFilters(RF)列表。每个RF都有过滤器,这些过滤器可以是String或Integer类型。
问题是过滤器是动态创建的,可以是String或Integer值,所以我们可以:
Filter1 = Filter {operation = (==) 5, value = 3}
Filter2 = Filter {operation = (==) "hello", value = "hello"}
两个过滤器都包含在同一个MRF中!
我想避免使用BasicTypes数据,并设置泛型类型,但是如果放置operation :: a -> Bool
那么所有Filter应该是相同的类型(所以我不能像{{1和} Integer -> Bool
在同一个列表中。)
你有什么建议?谢谢!
PS:我已经尝试使用TypeRep类型,但我无法找到解决方案
答案 0 :(得分:2)
这对你有用吗?
data Filter a = Filter { operation :: a -> Bool, value :: a }
data RF a = RF { event :: String; filters :: [ Filter a ] }
data MRF a = MRF { lastValue :: a, requestedFilters :: [RF a] }
在RF a
中,所有过滤器都必须是Filter a
类型。
<强>更新强>
我希望在RF中有一个字符串过滤器列表,然后是另一个带有Integer列表的RF,然后是带有Floats列表的其他RF,依此类推。我希望列表中的所有RF(MRF)。
这个怎么样:
data MFRList = MRFList
{ integerMRFs :: [ MRF Integer ]
, stringMRFs :: [ MRF String ]
, floatMRFs :: [ MRF Float ]
}
根据需要添加任意数量的字段。
答案 1 :(得分:1)
对此的基本解决方案是为Filter
使用两个构造函数:
data Filter
= FilterI {
operationI :: Int -> Bool,
valueI :: Int
}
| FilterS {
operationS :: String -> Bool,
valueS :: String
}
使用GADT的更高级替代方案:
-- singleton
data BasicType t where
BasicI :: BasicType Int
BasicS :: BasicType String
data Filter where
Filter ::
{ ty :: BasicType t
, operation :: t -> Bool
, value :: t
} -> Filter
请注意,上面重要的是可以在运行时测试字段ty
,以便我们可以发现实际上是哪种类型t
。例如:
useFilter :: Filter -> Int
useFilter (Filter BasicI op v) = v -- we know it's Int
useFilter (Filter BasicS op v) = length v -- we know it's String
我们也可以避免GADT并仅使用普通的存在类型:
data Filter where
Filter ::
{ operation :: t -> Bool
, value :: t
} -> Filter
但是通过这种方式,Filter
实际上与Bool
同构:我们无法对value
做任何事情,除非将其用作Filter
的参数。因此,这里的过滤器列表只是一个布尔列表,这是无趣的。
通常,如果您使用的是存在类型列表,则可能使用的是已知的antipattern。