# Derive parse from print with reasonable constraints

## or how to invert some functions

I will introduce simple motivation behind this whole story and shortly we will know how to derive `parse :: s → Maybe a`

from `print :: a → s`

, with reasonable constraints — `BoundedEnum a`

and `Ord s`

.

#### Motivation

Type system is a friend who’s got your back by making sure all inputs are encountered when writing functions. Usually `print :: a → s`

takes some type which is smaller (has smaller number of values) than its resulting type. But when writing `parse :: s -> Maybe a`

our friend can’t cover us anymore, as input type is bigger and we need to use `_ →`

in our case expression (it might be impossible to write down all the cases, take String for example).

data MyType = A | B | C

print :: MyType -> String

print = case _ of

A -> "a"

B -> "b"

C -> "c"

parse :: String -> Maybe MyType

parse = case _ of

"a" -> Just A

"b" -> Just B

"c" -> Just C

_ -> Nothing

Here we also have a decent amount of repetition. Also this code can get out of sync in many ways like incorrect change during merge, typo, etc.

#### Solution

If you are unfamiliar with BoundedEnum you should definitely check it out. How it helps us is that it gives us a way to generate all values of a type implementing this type class:

all ∷ ∀ a. BoundedEnum a ⇒ Array a

all = oneOf (upFromIncluding bottom)

Once we have `all`

values of a type we can apply `print`

to each and every one of them and use results as a key for some lookup dictionary:

mkDict ∷ ∀ s a. Ord s ⇒ BoundedEnum a ⇒ (a → s) → Map s a

mkDict print = fromFoldable $ all <#> \x → print x `Tuple` x

Now we can now write a function which takes `print`

and gives back `parse`

(note we use let binding and lambda in the end, so that dictionary is generated only once)

mkParse ∷ ∀ s a. Ord s ⇒ BoundedEnum a ⇒ (a → s) → (s → Maybe a)

mkParse print = let dict = mkDict print in \s -> lookup s dict