Question

I'm working on an applicative functor that contains a monoid to "view" the execution. However, sometimes I don't care about this part at all, so the choice of monoid is irrelevant as it will never be consumed. I've simplified what I have into:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}

import GHC.Exts

class Render a b where render :: a -> b
instance Render a () where render = const ()

class Merge a where
  type Renderer a b :: Constraint
  merge :: Renderer a b => a -> b

data Foo = Foo Bool

instance Merge Foo where
  type (Renderer Foo) m = (Render Bool m)
  merge (Foo b) = render b

Render is used to transform various as into a single b. Merge is a big simplification of my actual functor, but the point is it contains a type family/constraint and my intention of that is to specify exactly what Renderers a Merge requires.

Now, I might want to "run" the Merge, but discard the view, which is akin to something like:

runFoo :: Merge a => a -> Int
runFoo x = case merge x of () -> 5

But this will fail because:

Could not deduce (Renderer a ()) arising from a use of merge

I chose () as my monoid because forall a, we have an instance of Render a (). So if there was a way to say that Merge a just means a collection Render constraints then this would work fine. Of course, Merge a is more general than that - it could add arbitrary constraints, which explains the compilation error.

Is there anyway to achieve what I want without changing the signature of runFoo?

Was it helpful?

Solution

This might not scale if you have a lot of these cases, but this works:

class Renderer a () => Merge a where
  ...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top