Suppose I have a list fns
of partial functions from a
to b
, which I represent as functions from a
to Maybe b
, and I have an object x
of type a
. Suppose now that I want to define another function from a
to Maybe b
which takes the value of the first f x
that is not Nothing
, if such an f
exists in fns
, or the value Nothing
if no such f
exists. So basically it outputs f x
for the first f
that works, or Nothing
if no f
works.
It isn't hard to come up with some code that does the job. For example, one can create a list [f x| f <- fns]
remove all the Nothing
s from it, and then take the head of the resulting list, or Nothing
if that list is empty. But that feels clumsy, and this seems like the kind of general situation for which there is a much more stylish implementation using some built-in function in Haskell. If so, then I'd be interested to know what it is.
If you call a multi-parameter function with less than its total number of parameters, then you are partially applying the function. Here we call sum , our previously defined two-parameter function, with only one argument and receive a new function.
From HaskellWiki. A partial function is a function that is not defined for all possible arguments of the specified type. Examples in the Haskell standard library are: head , tail : undefined for empty lists. (!!) : undefined if the index is at least as big as the list length.
() is very often used as the result of something that has no interesting result. For example, an IO action that is supposed to perform some I/O and terminate without producing a result will typically have type IO () .
The Either type is sometimes used to represent a value which is either correct or an error; by convention, the Left constructor is used to hold an error value and the Right constructor is used to hold a correct value (mnemonic: "right" also means "correct").
Warning: This is a really non-standard solution. But I personally really like it for its elegance - and the underlying mind-bending.
On https://wiki.haskell.org/Pointfree you can find a function named swing
. Its implementation and type are confusing at first:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing = flip . (. flip id)
You can get a first idea of what it does when you see its fully applied form:
swing f c a = f ($ a) c
In conjunction with other higher-order functions it does things that almost look like magic. Examples from the link:
swing map :: [a -> b] -> a -> [b]
swing any :: [a -> Bool] -> a -> Bool
swing foldr :: b -> a -> [a -> b -> b] -> b
swing zipWith :: [a -> b -> c] -> a -> [b] -> [c]
swing find :: [a -> Bool] -> a -> Maybe (a -> Bool)
swing partition :: [a -> Bool] -> a -> ([a -> Bool], [a -> Bool])
All these functions do exactly what you would assume from the types. (But note that the wiki is a little out of date. By now, most of these functions automatically work for any Foldable
type.)
The function that you search could start from
swing mapMaybe :: [a -> Maybe b] -> a -> [b]
and then apply listToMaybe
. (Both functions are from Data.Maybe
)
A more general form would be
swing mapM :: (Monad m, Traversable t) => t (a -> m b) -> a -> m (t b)
so for example (using the ClassyPrelude
for full generality at the cost of some constraint noise, with headMay
as a more general form of listToMaybe
):
f :: (Traversable t, MonoFoldable (t b), Element (t b) ~ b)
=> t (a -> Maybe b) -> a -> Maybe b
f functions x = join $ headMay <$> swing mapM functions x
Yes, it might turn your head into mush - but it's like bending your head to see a smiley, only with your whole mind.
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