有没有办法在Haskell中有一个没有相同类型的对的列表,并使函数遍历它。例如:
a = [(1, "uno"), (2, True), (3, 5)]
想要根据第二个值的类型应用函数,类似于评估对f :: [(Int, #)] -> [a].
的组合的函数
答案 0 :(得分:7)
To a first approximation,不,这是不可能的。首先标准化值,例如通过将一些类多态函数应用于每个第二个参数,然后将它们放入元组中。
答案 1 :(得分:5)
只需将值包装在sum-type中。如,
data StringOrBoolOrInt =
StringOrBoolOrInt_String String |
StringOrBoolOrInt_Bool Bool |
StringOrBoolOrInt_Int Int
a :: [(Int, StringOrBoolOrInt)]
a =
[
(1, StringOrBoolOrInt_String "uno"),
(2, StringOrBoolOrInt_Bool True),
(3, StringOrBoolOrInt_Int 5)
]
答案 2 :(得分:2)
正如其他人所说的那样,这个问题没有解决方案。但你真正的问题是你的数据不是由元组列表描述的 - 根据定义,列表是同质的(所有元素包含相同的类型),而你的数据是异质的。
如果你想根据类型编写一个函数,你必须以某种方式在类型级别上存储类型。
您的示例数据实际上是由Prod ((,) Integer) '[String, Bool, Integer]
类型描述的,其中Prod
是以下类型:
data Prod f (xs :: [a]) where
P0 :: Prod f '[]
(:>) :: f x -> Prod f xs -> Prod f (x ': xs)
infixr 5 :>
对于某些类型列表Prod ((,) Integer) xs
,或更一般地xs
。
您的示例值是
a = (1, "uno") :> (2, True) :> (3, 5) :> P0
您可以使用常规方法(即类型类)对这些类型进行分支。假设有一个这样的类:
class HasFoo x where
foo :: x -> Integer
instance HasFoo String where foo = fromIntegral . length
instance HasFoo Bool where foo = fromIntegral . fromEnum
instance HasFoo Integer where foo = id
您可以将此类foo
功能应用于产品的每个元素
type family All (c :: k -> Constraint) (xs :: [k]) :: Constraint where
All c '[] = ()
All c (x ': xs) = (c x, All c xs)
-- example operation: add everything
fooProd :: All HasFoo xs
=> Prod ((,) Integer) xs
-> Integer
fooProd P0 = 0
fooProd ((i, x) :> ps) = i + foo x + fooProd ps
这需要一些GHC扩展,至少TypeFamilies
,GADTs
,ConstraintKinds
,DataKinds
,PolyKinds
。