`HFix`如何在Haskell的multirec包中工作?

时间:2012-03-15 18:22:10

标签: haskell types generic-programming multirec

我理解常规定点型组合器,我想我理解高阶固定n型组合器,但HFix使我望而却步。您能举例说明一组数据类型及其(手动派生的)固定点,您可以将HFix应用于。{/ p>

1 个答案:

答案 0 :(得分:5)

自然参考是论文Generic programming with fixed points for mutually recursive datatypes  解释multirec package的地方。

HFix是用于相互递归数据类型的fixpoint类型组合器。  本文第3.2节对此进行了详细解释,但其思路是  概括这种模式:

 Fix :: (∗ -> ∗) -> ∗
 Fix2 :: (∗ -> ∗ -> ∗) -> (∗ -> ∗ -> ∗) -> ∗

 Fixn :: ((∗ ->)^n * ->)^n ∗
 ≈
 Fixn :: (*^n -> *)^n -> *

要限制它执行固定点的类型数量,它们使用类型构造函数  而不是* ^ n。他们举了一个AST数据类型的例子,相互递归  本文有三种类型。我提供的可能是最简单的例子。让  我们HFix这种数据类型:

data Even = Zero | ESucc Odd deriving (Show,Eq)
data Odd  = OSucc Even       deriving (Show,Eq)

让我们在4.1节中介绍此数据类型的特定于族的GADT。

data EO :: * -> * where
  E :: EO Even
  O :: EO Odd

EO Even意味着我们带着偶数。  我们需要El实例才能工作,它说明了哪个具体的构造函数  我们分别在撰写EO EvenEO Odd时参考。

instance El EO Even where proof = E
instance El EO Odd  where proof = O

这些用作HFunctor instance的约束  I

现在让我们为偶数和奇数数据类型定义模式函子。  我们使用图书馆的组合器。 :>:类型构造函数标记  带有类型索引的值:

type PFEO = U      :>: Even   -- ≈ Zero  :: ()      -> EO Even
        :+: I Odd  :>: Even   -- ≈ ESucc :: EO Odd  -> EO Even
        :+: I Even :>: Odd    -- ≈ OSucc :: EO Even -> EO Odd

现在我们可以使用HFix来解决这个模式仿函数的问题:

type Even' = HFix PFEO Even
type Odd'  = HFix PFEO Odd

这些现在与EO Even和EO Odd同构,我们可以使用  hfrom and hto functions  如果我们将其作为Fam的实例:

type instance PF EO = PFEO

instance Fam EO where
  from E Zero      = L    (Tag U)
  from E (ESucc o) = R (L (Tag (I (I0 o))))
  from O (OSucc e) = R (R (Tag (I (I0 e))))
  to   E (L    (Tag U))           = Zero
  to   E (R (L (Tag (I (I0 o))))) = ESucc o
  to   O (R (R (Tag (I (I0 e))))) = OSucc e

一个简单的小测试:

test :: Even'
test = hfrom E (ESucc (OSucc Zero))

test' :: Even
test' = hto E test

*HFix> test'
ESucc (OSucc Zero)

使用代数将EvenOdd转换为Int值的另一项愚蠢测试:

newtype Const a b = Const { unConst :: a }

valueAlg :: Algebra EO (Const Int)
valueAlg _ = tag (\U             -> Const 0)
           & tag (\(I (Const x)) -> Const (succ x))
           & tag (\(I (Const x)) -> Const (succ x))

value :: Even -> Int
value = unConst . fold valueAlg E