Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell class dependencies

The following code doesnt compile:

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

The error is Could not deduce (Foo f) arising from a use of 'getInt' from the context (Bar b)

I know I can fix the error by changing the class for Bar as follows:

class Foo f => Bar f b where
  getFooFromBar :: b -> f

But I would prefer if I didnt have to add f to all the instance signatures of Bar.

Is there a way to do this by only keeping the Foo f constraint only on the getFooFromBar signature, rather than the whole class?

like image 747
tmortiboy Avatar asked Jul 27 '26 23:07

tmortiboy


1 Answers

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 
like image 184
duplode Avatar answered Jul 29 '26 16:07

duplode



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!