不同类型的元组

时间:2016-08-02 18:15:59

标签: haskell

有没有办法在Haskell中有一个没有相同类型的对的列表,并使函数遍历它。例如:

a = [(1, "uno"), (2, True), (3, 5)]

想要根据第二个值的类型应用函数,类似于评估对f :: [(Int, #)] -> [a].的组合的函数

3 个答案:

答案 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扩展,至少TypeFamiliesGADTsConstraintKindsDataKindsPolyKinds