我应该如何在haskell中使用constrant表达相互递归的数据类型?

时间:2015-08-06 19:56:57

标签: haskell

我自己不是很清楚,所以如果我的描述也不够清楚,请告诉我。

所以,我有两个班级:

class Prop1 a b | a -> b
class Prop2 c d | c -> d

和数据类型:

data X y z

他们之间的关系是:

  1. Xz的容器,y作为辅助容器。
  2. 容器y应包含另一组实例X y z
  3. y满足Prop1,即关注:

    instance Prop1 y (X y z)

  4. X本身满足Prop2,因此:

    instance Prop2 (X y z) z

  5. 所以当我定义X的实例时,我觉得自己乱七八糟,我写了类似的东西:

    instance Prop1 y (X y z) => Prop2 (X y z) z
    

    但是GHC似乎对此并不满意,并要求我添加FlexibleContextsUndecidableInstances,这些都让我感觉不安全。

    我读到将约束放在data上并不好,但我尝试了它并没有帮助:

    data Prop1 y (X y z) => X y z
    

    我应该如何在Haskell中处理它?<​​/ p>

1 个答案:

答案 0 :(得分:5)

UndecidableInstances可以安全使用,它只是意味着编译器不知道它能够终止类型检查/解析约束。 UndecidableInstances最糟糕的结果是编译器无法终止。我们可以看到编译器通过完成一个示例程序来终止。

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}

class Prop1 a b | a -> b
class Prop2 c d | c -> d

data X y z = X

instance Prop1 y (X y z) => Prop2 (X y z) z

-- An example Y and checking Prop2
data Y = Y

instance Prop1 Y (X Y ())

main :: Prop2 (X Y ()) () => IO ()
main = print "checked"

我们必须为z个实例选择Prop1 Y x的具体类型;基本上y正在确定z。我为()选择了Y;可能有另一个Y'具有不同的z

类型系列

如果您不想使用UndecidableInstances,可以使用TypeFamilies代替FunctionalDependencies

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}

class Prop1 a where
    type B a :: *

class Prop2 c where
    type D c :: *

data X y z = X

instance (Prop1 y, B y ~ (X y z)) => Prop2 (X y z) where
    type D (X y z) = z

-- An example Y and get the compiler to run all the way to requiring FlexibleContexts 
data Y = Y

instance Prop1 Y where
    type B Y = X Y ()

main :: Prop2 (X Y ()) => IO ()
main = print "checked"