以下代码无法编译:
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
签名上,而不是整个类?
答案 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