How to avoid clumsy constraints with IsoPrism?


I have record types with a parameter which might be Identity (for JSON encoding) or RemoteData (for partial representation in a structured UI editor).
I decided to define lenses/prisms for these types, because there are a lot of places use with them. A lens chain composed of precooked combinators breaks in the middle on fields with types such as f (Foo f).

I defined a class IsoPrism (I coined the name, because I don’t know the well known one)

class IsoPrism t a | t -> a where
  _theVal :: Prism' t a

instance IsoPrism (Maybe a) a where
  _theVal = _Just

instance IsoPrism (Identity a) a where
  _theVal = prism' Identity (Just <<< unwrap)

With IsoPrism functions built on top the lenses could be f polymophic:

setLearningRate :: forall f a.
  IsoPrism (f a) a =>  
  ChartExprFilterBodyT f ->
  ChartExprFilterBodyT f
setLearningRate = p .~ 0.5
    p = _predicate <<< _theVal <<< _AcceptWithSvm <<<
      _svmInputParams <<< _theVal <<< _XgBoost <<< _learningRate

but type checker requires a list of complicated constrains and makes less convenient:

setLearningRate :: forall f.
  IsoPrism (f (ChartPredicateT f)) (ChartPredicateT f) =>
  IsoPrism (f SvmInputParams) SvmInputParams =>

No type class instance was found for

Project.ChartPredicate.IsoPrism (f3 (ChartPredicateT f3))
                                       (ChartPredicateT t4)

Some definitions mentioned the code above:

type ChartPredicate = ChartPredicateT Identity

type ChartExprFilterBodyT f =
  { predicate :: f (ChartPredicateT f)
_predicate :: forall a r. Lens' { predicate :: a | r } a
_predicate = lens _.predicate $ _ { predicate = _ }

_AcceptWithSvm :: forall f. Prism' (ChartPredicateT f) (SvmRuleT f)
_AcceptWithSvm =
  prism' AcceptWithSvm $
    case _ of
      AcceptWithSvm b -> Just b
      _ -> Nothing

Do you actually need a Prism? It seems like a Traversal would be sufficient for this example, in which case just use traversed instead of your _theVal—no new classes required, since Maybe and Identity are both Traversable.

Edit: On second look, for just a setter like in this example you can even use humble map.