我自己不是很清楚,所以如果我的描述也不够清楚,请告诉我。
所以,我有两个班级:
class Prop1 a b | a -> b
class Prop2 c d | c -> d
和数据类型:
data X y z
他们之间的关系是:
X
是z
的容器,y
作为辅助容器。y
应包含另一组实例X y z
。 y
满足Prop1
,即关注:
instance Prop1 y (X y z)
X
本身满足Prop2
,因此:
instance Prop2 (X y z) z
所以当我定义X
的实例时,我觉得自己乱七八糟,我写了类似的东西:
instance Prop1 y (X y z) => Prop2 (X y z) z
但是GHC似乎对此并不满意,并要求我添加FlexibleContexts
和UndecidableInstances
,这些都让我感觉不安全。
我读到将约束放在data
上并不好,但我尝试了它并没有帮助:
data Prop1 y (X y z) => X y z
我应该如何在Haskell中处理它?</ p>
答案 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"