In working with lenses, I occasionally have the need for some basic text parsing in the chain of optics. In one API I'm dealing with, there is a JSON field like this:
"timespent": "0.25",
Since it is incorrectly encoded as a string instead of a number, I can't just do the typical lens-aeson solution:
v ^? key "timespent" . _Double -- this doesn't work
So, I need this instead:
v ^? key "timespent" . _String . mystery
where the mystery optic needs to turn Text into a Double. I know that mystery could be typed as follows:
mystery :: Prism' Text Double
And I could built this as follows:
mystery = prism' (pack . show) (readMaybe . unpack)
And technically, this function could have an even more general type signature with Read and Show constraints, but that's not really what my question is about. What I don't like is the Prism is really too strong for what I'm doing. Most of the time, I'm interested in parsing but not is rendering it back to a string. So, I need either a Traversal or a Fold but I'm not sure which one, and I'm not sure how to build them. When I look at the type signature of ^? to find the minimum optic required, I see:
(^?) :: s -> Getting (First a) s a -> Maybe a
I can sort of understand what this means but not very well. So, to make my question clear, it is:
If I have a function f :: Text -> Maybe a, how can I turn this into a Traversal or a Fold? Thanks, and let me know if there is anything I can clarify.
I think what you want is a Getter:
_Read :: Read a => Getter Text (Maybe a)
_Read f = contramap g . f . g where g = readMaybe . unpack
In general, if you have x :: a -> b then \f -> contramap x . f . x is a Getter a b.
Then to get the a value out of the Maybe a, use traverse, so combined you have _Read . traverse which is a Read a => Fold Text a.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With