Haskell类依赖项

时间:2016-11-04 02:39:01

标签: haskell typeclass

以下代码无法编译:

class Foo f where
  getInt :: f -> Int

class Bar b where
  getFooFromBar :: Foo f => b -> f

someFunction :: Bar b => b -> Int
someFunction bar = getInt $ getFooFromBar bar

错误为Could not deduce (Foo f) arising from a use of 'getInt' from the context (Bar b)

我知道我可以通过更改Bar的类来修复错误,如下所示:

class Foo f => Bar f b where
  getFooFromBar :: b -> f

但我希望如果我不必将f添加到Bar的所有实例签名中。

有没有办法只将Foo f约束仅保留在getFooFromBar签名上,而不是整个类?

1 个答案:

答案 0 :(得分:5)

  

但我希望如果我不必将f添加到Bar的所有实例签名中。

从技术上讲,你不需要这样做来编译你的例子。您可以使用类型注释来指定Foo中使用的someFunction实例,解决模糊类型变量错误。但是,您有一个更深层次的问题:

class Foo f where
  getInt :: f -> Int

class Bar b where
  getFooFromBar :: Foo f => b -> f

也就是说,出于所有实际目的,这是不可能的。 getFooFromBar的类型表示您可以使用它来生成任何类型f的结果,其实例为Foo。但是,如何为任何f实现此值?定义getFooFromBar时,达到任何特定实例是没有用的,因为您将从中获得Couldn't match type ‘f’ with ‘Blah’类型错误。对于那个问题的直接解决方案是您在问题中建议的问题:指定要通过Foo实例使用的Bar实例。您可能会发现使用类型系列更好,而不是多参数类型类:

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

class Foo f where
  getInt :: f -> Int

class Foo (FooBar b) => Bar b where
  type FooBar b :: *
  getFooFromBar :: b -> FooBar b

instance Foo Char where
   getInt = const 99

instance Bar Char where
  type FooBar Char = Char
  getFooFromBar = const 'a'

someFunction :: Bar b => b -> Int
someFunction = getInt . getFooFromBar
GHCi> someFunction 'z'
99