以下代码不编译:
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签名而不是整个类上来实现?
但我更愿意,如果我不必添加
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)