I've decided today is the day I fix some of my pure functions that are unnecessarily running in a monadic action. Here's what I have.
flagWorkDays :: [C.Day] -> Handler [WorkDay]
flagWorkDays dayList =
flagWeekEnds dayList >>=
flagHolidays >>=
flagScheduled >>=
flagASAP >>=
toWorkDays
Here is flagWeekEnds, as of now.
flagWeekEnds :: [C.Day] -> Handler [(C.Day,Availability)]
flagWeekEnds dayList = do
let yepNope = Prelude.map isWorkDay dayList
availability = Prelude.map flagAvailability yepNope
return $ Prelude.zip dayList availability
flagHolidays
follows a similar pattern. toWorkDays
just changes one type to another, and is a pure function.
flagScheduled
, and flagASAP
are monadic actions. I am not sure how to combine the monadic actions with the pure functions idiomatically in flagWorkDays
. Could someone help me fix flagWorkDays
, assuming flagWeekEnds
and flagHolidays
have been made pure?
Let's take a step back for a moment. You have two types of functions, some pure with types of the form a -> b
, and some monadic of type a -> m b
.
To avoid confusion, let's also stick with right-to-left composition. If you prefer to read left-to-right, just reverse the order of the functions and replace (<=<)
with (>=>)
, and (.)
with (>>>)
from Control.Arrow
.
There are then four possibilities for how these can be composed.
Pure then pure. Use regular function composition (.)
.
g :: a -> b
f :: b -> c
f . g :: a -> c
Pure then monadic. Also use (.)
.
g :: a -> b
f :: b -> m c
f . g :: a -> m c
Monadic then monadic. Use kleisli composition (<=<)
.
g :: a -> m b
f :: b -> m c
f <=< g :: a -> m c
Monadic then pure. Use fmap
on the pure function and (.)
to compose.
g :: a -> m b
f :: b -> c
fmap f . g :: a -> m c
Ignoring the specifics of the types involved, your functions are:
flagWeekEnds :: a -> b
flagHolidays :: b -> c
flagScheduled :: c -> m d
flagASAP :: d -> m e
toWorkDays :: e -> f
Let's go from the top. flagWeekEnds
and flagHolidays
are both pure. Case 1.
flagHolidays . flagWeekEnds
:: a -> c
This is pure. Next up is flagScheduled
, which is monadic. Case 2.
flagScheduled . flagHolidays . flagWeekEnds
:: a -> m d
Next is flagASAP
, now we have two monadic functions. Case 3.
flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
:: a -> m e
And finally, we have the pure function toWorkDays
. Case 4.
fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
:: a -> m f
And we're done.
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