以下代码无法编译:
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
错误是无法从上下文 (Bar b) 中使用“getInt”来推断 (Foo f)
我知道我可以通过更改 Bar
的类来修复错误,如下所示:
class Foo f => Bar f b where
getFooFromBar :: b -> f
但我更希望不必将 f
添加到 Bar
的所有实例签名中。
有没有办法通过仅在 getFooFromBar
签名而不是整个类上保留 Foo f
约束来实现此目的?
最佳答案
But I would prefer if I didnt have to add
f
to all the instance signatures ofBar
.
从技术上讲,您不需要这样做来编译示例。您可以使用类型注释来指定在 someFunction
中使用哪个 Foo
实例,从而解决不明确的类型变量错误。但是,您有一个更深层次的问题:
class Foo f where
getInt :: f -> Int
class Bar b where
getFooFromBar :: Foo f => b -> f
也就是说,出于所有实际目的,这是不可能的。 getFooFromBar
的类型表明您可以使用它来生成具有 Foo
实例的 any 类型 f
的结果>。但是如何为任何 f
实现这个值呢?定义 getFooFromBar
时到达任何特定实例是没有用的,因为您将得到的只是 Couldn't match type 'f' with '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
GHCi> someFunction 'z'
99
关于Haskell 类依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40414449/