我今天决定在我修复一些不必要的monadic动作的纯函数的那一天。这就是我所拥有的。
flagWorkDays :: [C.Day] -> Handler [WorkDay]
flagWorkDays dayList =
flagWeekEnds dayList >>=
flagHolidays >>=
flagScheduled >>=
flagASAP >>=
toWorkDays
截至目前,这是flagWeekEnds。
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
遵循类似的模式。 toWorkDays
只是将一种类型更改为另一种类型,并且是纯函数。
flagScheduled
和flagASAP
是monadic行动。我不确定如何在flagWorkDays
中以惯用方式将monadic动作与纯函数结合起来。有人可以帮我修复flagWorkDays
,假设flagWeekEnds
和flagHolidays
是纯净的吗?
答案 0 :(得分:29)
让我们退一步。您有两种类型的函数,一些是纯函数,其格式为a -> b
,另一些函数为a -> m b
。
为避免混淆,让我们坚持从右到左的构图。如果您希望从左向右阅读,只需颠倒函数的顺序,将(<=<)
替换为(>=>)
,将(.)
替换为(>>>)
Control.Arrow
然后有四种可能性来组成这些。
纯净然后纯粹。使用常规函数组合(.)
。
g :: a -> b
f :: b -> c
f . g :: a -> c
纯粹的monadic 。也可以使用(.)
。
g :: a -> b
f :: b -> m c
f . g :: a -> m c
Monadic然后是monadic 。使用kleisli撰写(<=<)
。
g :: a -> m b
f :: b -> m c
f <=< g :: a -> m c
Monadic然后纯粹。在纯函数上使用fmap
并使用(.)
撰写。
g :: a -> m b
f :: b -> c
fmap f . g :: a -> m c
忽略所涉及类型的细节,您的功能是:
flagWeekEnds :: a -> b
flagHolidays :: b -> c
flagScheduled :: c -> m d
flagASAP :: d -> m e
toWorkDays :: e -> f
让我们从顶部开始。 flagWeekEnds
和flagHolidays
都是纯粹的。案例1。
flagHolidays . flagWeekEnds
:: a -> c
这很纯粹。接下来是flagScheduled
,这是monadic。案例2。
flagScheduled . flagHolidays . flagWeekEnds
:: a -> m d
接下来是flagASAP
,现在我们有两个monadic函数。案例3。
flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
:: a -> m e
最后,我们有了纯函数toWorkDays
。案例4。
fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
:: a -> m f
我们已经完成了。
答案 1 :(得分:5)
这不是很困难。您基本上只需将(>>=)
替换为(.)
并翻转操作数顺序。 do
语法可能有助于澄清。我还使用Kleisli组合子(鱼)(<=<) :: (b -> m c) -> (a -> m b) -> a -> m c
制作了示例pointfree,对于monad来说基本上是(.)
。
import Control.Monad
flagWorkDays :: [C.Day] -> Handler [WorkDay]
flagWorkDays =
fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
答案 2 :(得分:5)
要填写FUZxxl的答案,让我们纯化flagWeekEnds
:
flagWeekEnds :: [C.Day] -> [(C.Day,Availability)]
flagWeekEnds days = days `zip` map (flagAvailability . isWorkDay) days
您经常在变量名称(day
- &gt; days
)之后添加一个“s”(如同您使用英语中的复数形式)。