У меня есть коллекция записей, распределенных по нескольким типам в большом приложении на Haskell, которые ссылаются друг на друга. Все задействованные типы реализуют общий класс типов. Класс типов содержит функции, которые работают с переменной и всеми ее дочерними элементами, во многом как функция uniplate para
.
Это упрощенный пример кода, который я хотел бы построить. Возможно ли (и разумно) получить универсальную функциональность для сворачивания полей записи, которые реализуют данный класс типов в GHC ...
{-# LANGUAGE RankNTypes #-}
myPara :: forall a r . (Data a, Foo a)
=> (forall b . Foo b => b -> [r] -> r)
-> a
-> r
-- or as a fold
myFold :: forall a r . (Data a, Foo a)
=> (forall b . Foo b => r -> b -> r)
-> r
-> b
-> r
Но достаточно ли он универсален для работы с произвольным классом типов?
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Generics.Uniplate.Data
class Foo a where
fooConst :: a -> Int
data Bar = Bar {barBaz :: Baz} deriving (Typeable, Data)
instance Foo Bar where
fooConst _ = 2
data Baz = Baz {barBar :: Bar} deriving (Typeable, Data)
instance Foo Baz where
fooConst _ = 3
func :: Int
func = foldl (\ x y -> x + fooConst y) 0 instances where
instances :: forall a . (Data a, Foo a) => [a]
instances = universeBi bar
bar = Bar{barBaz = baz}
baz = Baz{barBar = bar}
Компиляция с помощью GHC 7.2.1 (очевидно) завершается неудачей:
Repro.hs:21:42:
Ambiguous type variable `a0' in the constraints:
(Data a0) arising from a use of `instances' at Repro.hs:21:42-50
(Foo a0) arising from a use of `instances' at Repro.hs:21:42-50
Probable fix: add a type signature that fixes these type variable(s)
In the third argument of `foldl', namely `instances'
In the expression: foldl (\ x y -> x + fooConst y) 0 instances
In an equation for `func':
func
= foldl (\ x y -> x + fooConst y) 0 instances
where
instances :: forall a. (Data a, Foo a) => [a]
instances = universeBi bar
bar = Bar {barBaz = baz}
baz = Baz {barBar = bar}