Как утверждают другие, данная проблема не имеет решения. Но ваша реальная проблема заключается в том, что ваши данные не описываются списком кортежей. По определению список гомогенный (все элементы содержат один и тот же тип), в то время как ваши данные являются гетерогенными.
Если вы хотите написать функцию в зависимости от типа, вы должны как-то сохранить тип на уровне уровня.
Ваш пример данных фактически описывается типом 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
.
Я не думаю, что в настоящее время это возможно без расширения 'ImpredicativeTypes', которое в настоящее время [действительно не работает] (http://stackoverflow.com/q/33741334/465378). –
@AlexisKing 'ImpredicativeTypes' вам не поможет. Импрессивность позволяет вам параметризовать типы с помощью 'forall'-quantified типов, например, для создания _homogeneous_ списка полиморфных функций. OP хочет построить _heterogeneous_ список мономорфных кортежей. –
@jonaprieto Чего вы пытаетесь достичь? Самый простой способ - создать тип суммы и выполнить анализ событий во время выполнения: 'a :: [(Int, Either Bool String)]' –