首页 文章

Haskell无法从Context错误推断出......

提问于
浏览
8

我有类型类,对于所有这些类我都希望有一些常见的行为 . 我的问题在以下代码中解释:

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 返回刚性类型值,我该如何编写这部分代码?

2 回答

  • 11

    签名 method :: (A a, B b) => x -> a -> b 承诺 method 适用于 every 对类型 (a, b)a A 的实例和 b B 的实例,但您将其定义为仅适用于两种特定类型 .

    这与Java等中的接口根本不同,其中被调用者选择使用哪种类型,调用者唯一知道的是接口X被实现 . 在Haskell中,给定这样的签名,调用者决定使用哪些类型(这里,作为第二个参数传递什么类型以及应返回什么类型)并且被调用者必须能够提供所需的功能(只要需要) types是所需类的实例 .

    没有类 AB 中的任何方法来分别分析该类实例的构造值,除了 undefined 之外你不能实现 method (由于 seq 可能存在不同程度的未定义),所以你必须告诉全世界你事实上正在使用 TU .

    另一种方法是使 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 ...
    
  • 3

    很难想出一种方法来拯救你的榜样(由于Daniel Fischer提到的原因) . 如果你有两个完全不相关的类型A和B,你应该如何 Build 一般连接?所以你可以将两者放在一起,但我怀疑这是你想要的:

    {-# 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 U 旁边有 A2B T V 之类的实例时,这个设计就不会出现问题 .

相关问题