函数列表中的泛型类型

时间:2016-08-14 22:29:22

标签: haskell

我有下一个结构:

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类型,但我无法找到解决方案

2 个答案:

答案 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