我有类型类,我希望所有类型都有一些常见的行为。我的问题在以下代码中解释:
class A a class B b class X x where method :: (A a, B b) => x -> a -> b data T = L | M | N data U = P | Q | R instance A T instance B U data Y = ZZZ instance X Y where method _ L = P method _ M = Q method _ N = R
当我加载此模块时,出现以下错误:
example.hs:19:14: Could not deduce (a ~ T) from the context (A a, B b) bound by the type signature for method :: (A a, B b) => Y -> a -> b at example.hs:(17,5)-(19,18) `a' is a rigid type variable bound by the type signature for method :: (A a, B b) => Y -> a -> b at example.hs:17:5 In the pattern: N In an equation for `method': method _ N = R In the instance declaration for `X Y' example.hs:19:18: Could not deduce (b ~ U) from the context (A a, B b) bound by the type signature for method :: (A a, B b) => Y -> a -> b at example.hs:(17,5)-(19,18) `b' is a rigid type variable bound by the type signature for method :: (A a, B b) => Y -> a -> b at example.hs:17:5 In the expression: R In an equation for `method': method _ N = R In the instance declaration for `X Y' Failed, modules loaded: none.
在这种情况下我无所适从。即使T和U是A和B的实例,我也会收到此错误。如果我无法从method
返回刚性类型值,我该如何编写此部分?
答案 0 :(得分:11)
签名method :: (A a, B b) => x -> a -> b
承诺method
适用于每个类型(a, b)
,其a
个实例为A
, b
B
的实例,但您将其定义为仅适用于两种特定类型。
这与Java等中的接口根本不同,其中被调用者选择使用哪种类型,调用者唯一知道的是接口X的实现。在Haskell中,给定这样的签名,调用者决定使用哪些类型(这里,作为第二个参数传递什么类型以及应返回什么类型)并且被调用者必须能够提供所需的功能(只要需要) types是所需类的实例。)
如果没有类A
和B
中的任何方法来分别分析该类实例的构造值,除method
之外不能实现undefined
(不同程度)由于seq
)可能导致未定义,因此您必须告诉全世界您实际上正在使用T
和U
。
另一种方法是使X
成为多参数类型
{-# LANGUAGE MultiParamTypeClasses #-}
class (A a, B b) => X x a b where
method :: x -> a -> b
但是,这可能需要功能依赖来解析实例。另一种方法是使用相关类型,
{-# LANGUAGE TypeFamilies #-}
class X x where
type AType x
type BType x
method :: x -> AType x -> BType x
instance X Y where
type AType Y = T
type BType Y = U
method ...
答案 1 :(得分:3)
很难想出一种方法来拯救你的榜样(由于Daniel Fischer提到的原因)。如果你有两个完全不相关的类型A和B,你应该如何建立一般连接?所以你可以把它们放在一起,但我怀疑这是你想要的:
{-# LANGUAGE MultiParamTypeClasses #-}
class A2B a b where
convert :: a -> b
data T = L | M | N
data U = P | Q | R
instance A2B T U where
convert L = P
convert M = Q
convert N = R
data Y = ZZZ
class X x where
method :: (A2B a b) => x -> a -> b
instance X Y where
method _ t = convert t
这种设计也不是很稳定:当你希望在A2B T V
旁边有A2B T U
这样的实例时,你会遇到麻烦。