Haskell类依赖项

tmo*_*boy 3 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
Run Code Online (Sandbox Code Playgroud)

错误是 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
Run Code Online (Sandbox Code Playgroud)

但我更愿意,如果我不必添加f到所有的实例签名Bar.

有没有办法通过仅将Foo f约束仅保留在getFooFromBar签名而不是整个类上来实现?

dup*_*ode 5

但我更愿意,如果我不必添加f到所有的实例签名Bar.

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

class Foo f where
  getInt :: f -> Int

class Bar b where
  getFooFromBar :: Foo f => b -> f
Run Code Online (Sandbox Code Playgroud)

也就是说,出于所有实际目的,不可能.该类型的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
Run Code Online (Sandbox Code Playgroud)
GHCi> someFunction 'z'
99 
Run Code Online (Sandbox Code Playgroud)