我有一个记录集合,分布在一个大型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}
答案 0 :(得分:1)
你已经点击了Existential Antipattern. 除了需要编译器的情况之外,您不应该使用类型类 猜你的类型。类型x的值列表将保留类型x的值列表,无论您将实现什么类型类,并且您不能在此处破坏类型系统。
你可以:
使用上面建议的ad-hoc框类型。这简直太丑了。
使用消息传递实现通用接口。
数据Foo = Foo {fooConst :: Int}
bar = Foo 2
baz = Foo 3
答案 1 :(得分:0)
一段时间..
您是否尝试过存在量化的数据构建器?
data Foo = forall a. MyTypeClass a => Bar [a]
func (Bar l) = map typeClassMember a
现在,func
将适用于Foo类型的任何内容,它隐藏了内部类型。