A helper type to look for a Just in a pile of Maybes.
Let's imagine you have a FormError type like this:
type alias FormError =
{ password : Maybe PasswordStrengthError
, acceptedTerms : Maybe MustAcceptTermsError
}You might produce these values by validating a registration form. You'd augment the form with any errors you produced, and as the user updated the form, you would clear the error fields (until you validated it again).
You have a submit button but you want to disable it if there's an
error that needs correcting, so you add a disabled attribute
according to the condition Maybe.isJust formErrors. But eventually
the user will clear the last error and you'll have a FormError full of
Nothings. You need to convert that Just "empty" FormError into a
Nothing so that the submit button can be activated again.
You could write a function like this:
flatten : FormErrors -> Maybe FormErrors
flatten ({ password, acceptedTerms } as formErrors) =
case ( password, acceptedTerms ) of
( Nothing, Nothing ) ->
Nothing
_ ->
Just formErrorsBut this function is brittle. If you add a field to the FormErrors
type, this function needs to be updated too, and the compiler won't
help you.
Instead, this module provides an AnyJust type that re-uses the
constructor to your FormErrors type to ensure that every field is
checked for presence. You could re-write the flatten function with
it as:
flatten : FormErrors -> Maybe FormErrors
flatten formErrors =
AnyJust.start FormErorrs
|> AnyJust.check formErrors.password
|> AnyJust.check formErrors.acceptedTerms
|> AnyJust.finishAs the name implies, if any field is Just, then at the end, you wind
up with a Just FormErrors (produced by re-constructing it with the
values given). If no Just was provided to AnyJust.check, then you
end up with Nothing. The reconstruction of the FormErrors is
slightly inefficient, but in exchage, we can leverage the compiler to
complain if we add another field.
Start an AnyJust that has never seen a Just.
Feed a Maybe to the underlying type, checking if it's a Just.
Resolve the AnyJust, producing Just a if we ever saw a Just.
Functor map, just for completeness.
Be careful not to use this instead of check if you intend to check a
Maybe. If you do, the types will still work out, but the finish
function will not produce a Just at the end.
Applicative andMap, just for completeness.
The resulting AnyJust will register as having seen a Just if either
input saw a Just.
Be careful not to use this instead of check if you intend to check a
Maybe. If you do, the types will still work out, but the finish
function will not produce a Just at the end.
Monadic andThen, just for completeness.
The resulting AnyJust will register as having seen a Just if the
original AnyJust saw a Just or if the output AnyJust saw a
Just.
Be careful not to use this instead of check if you intend to check a
Maybe. If you do, the types will still work out, but the finish
function will not produce a Just at the end.
A utility type for checking for a
Justin a pile ofMaybes.It wraps some other type, typically a constructor, and as you feed it arguments using
check, it updates aBoolto see if it ever saw aJust. At first, thisBoolisFalse. It switches toTrueifcheckis ever given aJust.You can feel free to think of this type as a writer monad for a Bool. You can also feel free not to think of it that way, if you don't know what that means or find it confusing.