But I would prefer if I didnt have to add f
to all the instance signatures of Bar
.
Technically speaking, you don't need to do that to make your example compile. You can use a type annotation to specify which instance of Foo
you are using in someFunction
, solving the ambiguous type variable error. However, you have a deeper problem:
class Foo f where
getInt :: f -> Int
class Bar b where
getFooFromBar :: Foo f => b -> f
That is, for all practical purposes, impossible. The type of getFooFromBar
says you can use it to produce a result of any type f
that has an instance of Foo
. But how will you materialise this value for any f
? It is no use reaching for any specific instance when defining getFooFromBar
, as all you will get from that is a Couldn't match type ‘f’ with ‘Blah’
type error. The immediate solution to that is the one you suggested, for a different reason, in the question: specifying the instance of Foo
to use through the Bar
instance. You might find it nicer to do with a type family, rather than a multi-parameter type class:
{-# 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