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