Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turned-around Prisms and partial Isos #904

Open
yairchu opened this issue Dec 29, 2019 · 1 comment
Open

Turned-around Prisms and partial Isos #904

yairchu opened this issue Dec 29, 2019 · 1 comment

Comments

@yairchu
Copy link
Contributor

yairchu commented Dec 29, 2019

When experimenting with parsing and building using Prisms I found a need for "turned-around" Prisms (kind of like re but not becoming uni-directional) and "partial" Isos (conversion to both sides may fail).

I came up with implementations that seem to work nicely, Prisms composed with InvPrisms become PartialIsos, etc:

-- A partial variant of (#) for partial reviews
infixr 8 #?
(#?) :: Optic Tagged Maybe s t a b -> b -> Maybe t
f #? b = Just b & Tagged & f & unTagged

-- A Prism "turned around", i.e a getter but a partial review
type InvPrism s t a b =
    forall p f. (Profunctor p, Filterable f) => Optic p f s t a b

-- A partial iso-morphism, i.e a partial getter and partial review
type PartialIso s t a b =
    forall p f. (Choice p, Applicative f, Filterable f) => Optic p f s t a b

-- Turn APrism around
invPrism :: APrism b a t s -> InvPrism s t a b
invPrism p =
    dimap
    (review (reviewing (clonePrism p)))
    (mapMaybe (^? getting (clonePrism p)))

-- Create a PartialIso from two partial conversions
partialIso :: (s -> Maybe a) -> (b -> Maybe t) -> PartialIso s t a b
partialIso sma ams =
    dimap
    (maybe (Left ()) Right . sma)
    (catMaybes . either (const (pure Nothing)) (fmap ams)) .
    right'

-- Could this be done by `failing`?
failing' ::
    PartialIso s t a b ->
    Prism s t a b ->
    Prism s t a b
failing' i p =
    prism
    (\b -> fromMaybe (reviewing p # b) (i #? b))
    (\s -> maybe (matching p s) Right (s ^? getting i))
  • failing' is a parsing/building combinator - it first tries the given PartialIso in both parsing and building, and falls back to the given Prism. I called it failing' because to me it seems similar to failing, though trying to see if the latter can be generalised also to fit this use case seems over my head.
  • Note that InvPrism doesn't carry all of the same power as Prism does, i.e it can't support being an "inverted setter" if such operations existed as it's matching may simply fail and not fall back to type-change the structure.
@ekmett
Copy link
Owner

ekmett commented Nov 20, 2020

When working on early versions of lens we found that the profunctor version of things did lead naturally to 'inverse prisms' and 'inverse lenses', but that the mixed profunctor/functor encoding we wound up using in lens got in the way of flipping. I haven't thought about Filterable as a possible fix.

Sadly it isn't quite as pretty as the version you get out of the profunctor encoding where re and from and invPrism and the operation to turn back from an inverse prism to a prism, (and the equivalents for lenses and inverse lenses) all collapsed into precisely the same from combinator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants