Haskell类依赖项

Haskell类依赖项,haskell,typeclass,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 错误是无法从上下文(b栏)中推断出使用“getInt”时产生的(Foo f) 我知道我可以通过如下更改

以下代码未编译:

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
错误是
无法从上下文(b栏)中推断出使用“getInt”时产生的(Foo f)

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

class Foo f => Bar f b where
  getFooFromBar :: b -> f
但是如果我不必将
f
添加到
Bar
的所有实例签名中,我会更愿意这样做

是否有一种方法可以做到这一点,即只对
getFooFromBar
签名而不是整个类保留
Foo f
约束

但是如果我不必将
f
添加到
Bar
的所有实例签名中,我会更愿意这样做

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

class Foo f where
  getInt :: f -> Int

class Bar b where
  getFooFromBar :: Foo f => b -> f
就所有实际目的而言,这是不可能的。
getFooFromBar
的类型表示您可以使用它生成具有
Foo
实例的任何类型的
f
的结果。但是,对于任何
f
,您将如何实现该值?在定义
getFooFromBar
时,访问任何特定实例都是没有用的,因为您将从中得到的只是一个
无法将类型“f”与“Blah”匹配的类型错误。出于另一个原因,您在问题中建议的解决方案是:通过
Bar
实例指定要使用的
Foo
实例。您可能会发现使用类型族比使用多参数类型类更好:

{-# 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

我建议您重新考虑
getFooFromBar
的类型-它看起来似乎有一个
不明确的类型变量
错误。@Alec完整的错误确实表明
类型变量“f0”不明确
。可能重复
GHCi> someFunction 'z'
99