首页 文章

折叠Haskell中的多态列表

提问于
浏览
14

我有一个记录集合,分布在大型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}

2 回答

  • 1

    你已经击中Existential Antipattern.你不应该在这里破坏类型系统 .

    您可以:

    • 使用上面建议的ad-hoc框类型 . 这简直太丑了 .

    • 使用消息传递实现通用接口 .

    data Foo = Foo

    bar = Foo 2

    baz = Foo 3

  • 0

    已经有一段时间..

    您是否尝试过存在量化的数据构造函数?

    data Foo = forall a. MyTypeClass a => Bar [a]
    
    func (Bar l) = map typeClassMember a
    

    现在, func 将适用于Foo类型的任何内容,它隐藏了内部类型 .

相关问题