无法推断出两种约束类型是相同的

时间:2017-01-06 14:49:10

标签: haskell

我有几个类构成更广泛的层次结构的一部分,我正在尝试在DepTag上实现它们:

class StanfordType a where
  text :: a -> Text

class StanfordType a => Dep a where
  relation :: (StanfordType b) => a -> b

data DepTag a b where
  DepTag :: (StanfordType a) => Text -> a -> DepTag Text a

instance StanfordType (DepTag a b) where 
  text (DepTag s _) = s

instance Dep (DepTag a b) where 
  relation (DepTag _ r) = r

当我尝试编译时,我发出以下错误:

• Could not deduce: b ~ b1
  from the context: (a ~ Text, N.StanfordType b)
    bound by a pattern with constructor:
               DepTag :: forall b. N.StanfordType b => Text -> b -> DepTag Text b,
             in an equation for ‘relation’
    at src/NLP/Data.hs:17:45-54
  ‘b’ is a rigid type variable bound by
    the instance declaration at src/NLP/Data.hs:17:10
  ‘b1’ is a rigid type variable bound by
    the type signature for:
      relation :: forall b1. N.StanfordType b1 => DepTag a b -> b1
    at src/NLP/Data.hs:17:35
• In the expression: r
  In an equation for ‘relation’: relation (DepTag _ r) = r
  In the instance declaration for ‘N.Dep (DepTag a b)’
• Relevant bindings include
    r :: b (bound at src/NLP/Data.hs:17:54)
    relation :: DepTag a b -> b1 (bound at src/NLP/Data.hs:17:35)

我无法解释为什么编译器无法看到r类型签名中的relation(Dep)和b中的relation都是相同。我在这里错过了什么?

1 个答案:

答案 0 :(得分:4)

  

我无法解释为什么编译器无法看到关系(Dep)中的r和关系类型签名中的b都是相同的。

问题在于它们不一样。这里的问题是,relation :: (Dep a, StanfordType b) => a -> b必须能够返回每个有效的b。因此,虽然您对类型签名的理解是,您可以返回您(b的作者)希望它实际意味着的任何relation,您必须返回任何b我( relation)的来电者想要的。我们可以像这样明确区别(第二个变体不是实际的Haskell语法,第一个不是标准的Haskell):

relation :: forall b. (Dep a, StanfordType b) => a -> b -- Actual meaning
relation :: exists b. (Dep a, StanfordType b) => a -> b -- Your interpretation

因此,如果创建一个Foo类型,那就是StanfordType的实例:

newtype Foo = Foo | Bar
instance StanfordType Foo where
   text = pack "FooBar"

您现在可以使用GHCi验证,该分辨率实际上必须能够返回Foo类型的值:

 > :t resolution :: Dep a => a -> Foo
 resolution :: Dep a => a -> Foo :: Dep a => a -> Foo

当然,使用StanfordType实例创建任何未知类型的值是不可能的。特别是因为字面上每个类型都可以有一个StanfordType实例。

我们实际上可以使用存在主义来表达第二种类型:

data ExtStanfordType where
   EST :: StanfordType a => a -> ExtStanfordType

class StanfordType a => Dep a where
    relation :: a -> ExtStanfordType

instance Dep (DepTag a b) where
    relation = (DepTag _ r) = EST r

现在,解决方案可以返回StanfordType中包含的任何ExtStanfordType。然后,您可以像这样使用text

 textExt :: ExtStanfordType -> Text
 textExt (EST b) = text b

另请参阅:Existential type - Haskell Wiki