Closed treeowl closed 6 years ago
Urk. I hate how Github note things work. It would be much, much nicer to use Representable
here than Distributive
and Applicative
, but that would incur an adjunctions
dependency. We need the Applicative
to implement wanderMapping
and for several of the Mapping
instances. If we had Representable
instead of Distributive
, I think we could use Data.Functor.Rep.Co
to get everything we need.
Trying to pin down the representable functor to a function doesn't seem to work too well; things that can be coercions end up not. So I guess (Distributive f, Applicative f)
may be the way to go for now, sad as it is.
Is there some adjunction-like interaction happening between
Traversable1 t
<-> Apply f
Traversable t
<-> Applicative f
Functor f
<-> Representable f
(this is witnesed by Adjunction
?)
is this your, @treeowl reasoning for use of Representable
?FWIW: Settable
has also Traversable
. I guess it's is trivially satisfied by any Representable
functor.
I don't know any of this theory, really. Anything Distributive
should also support a Representable
instance (unique, but sadly only up to isomorphism). Using that allows more functions to be passed to roam (the payoff). It also, I believe, simplifies the Kleisli
and Star
instance constraints to eliminate the Applicative
and Monad
components. We keep tacking constraints onto Distributive
because (I think) we really want Representable
.
The trouble with Representable
, in some contexts, is that we need to expose a representation type as part of the API. I wonder if there's some way around that using TypeInType
And for usefulness: In profunctor based optics Representable
definition is simpler, as then one can define
setting
, otherwise we need to stick with collecting
only (or use p ~ (->)
constraint which I don't like).
type Setter s t a b = forall p. Mapping p => Optic p s t a b
type Optic p s t a b = p a b -> p s t
-- I don't see easy way to define without `Distributive` and `Applicative` only
setting :: ((a -> b) -> s -> t) -> Setter s t a b
setting f = roam $ \g s -> tabulate $ \idx ->
f (flip index idx . g) s
-- Distributive and Applicative constraint would be enough, if one don't need `setting`
collecting
:: (forall f. Representable f => (a -> f b) -> s -> f t)
-> Setter s t a b
collecting = roam
EDIT:
And because we have Representable f
, using Star f
, we can over
many inputs at once:
(it's not collectOf
, as that won't allow traverse'
to be there).
>>> overMany (mapped . traverse') (\i -> V2 (negate i) i) [[1,2],[3]]
V2 [[-1,-2],[-3]] [[1,2],[3]]
I don't know if this is useful or not, but
Mapping
supports aroam
method similar towander
.