如何用惯用的monadic动作组织我的纯函数

Mic*_*ard 17 monads haskell function-composition

我决定今天是我修复一些不必要地在monadic动作中运行的纯函数的那一天.这就是我所拥有的.

flagWorkDays :: [C.Day] -> Handler [WorkDay] 
flagWorkDays dayList =
   flagWeekEnds dayList >>=
   flagHolidays >>=
   flagScheduled >>=
   flagASAP >>=
   toWorkDays
Run Code Online (Sandbox Code Playgroud)

这是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
Run Code Online (Sandbox Code Playgroud)

flagHolidays遵循类似的模式.toWorkDays只是将一种类型更改为另一种类型,并且是纯函数.

flagScheduled,flagASAP是monadic行动.我不确定如何将monadic动作与惯用语中的纯函数结合起来flagWorkDays.有人可以帮我解决flagWorkDays,假设flagWeekEnds并且flagHolidays已经变得纯净了吗?

ham*_*mar 29

让我们退一步吧.你有两种类型的函数,一些是纯粹的表单类型a -> b,一些是monadic类型a -> m b.

为了避免混淆,让我们也坚持从右到左的构图.如果你喜欢阅读左到右,只是反转的功能的顺序和替换(<=<)(>=>),并(.)(>>>)Control.Arrow.

然后有四种可能性来组成这些.

  1. 纯净然后纯净.使用常规功能组合(.).

     g :: a -> b
     f :: b -> c
     f . g :: a -> c
    
    Run Code Online (Sandbox Code Playgroud)
  2. 纯粹的monadic.也用(.).

     g :: a -> b
     f :: b -> m c
     f . g :: a -> m c
    
    Run Code Online (Sandbox Code Playgroud)
  3. Monadic然后monadic.使用kleisli成分(<=<).

     g :: a -> m b
     f :: b -> m c
     f <=< g :: a -> m c
    
    Run Code Online (Sandbox Code Playgroud)
  4. Monadic然后纯洁.使用fmap的纯函数和 (.)作曲.

     g :: a -> m b
     f :: b -> c
     fmap f . g :: a -> m c
    
    Run Code Online (Sandbox Code Playgroud)

忽略所涉及类型的细节,您的功能是:

flagWeekEnds :: a -> b
flagHolidays :: b -> c
flagScheduled :: c -> m d
flagASAP :: d -> m e
toWorkDays :: e -> f
Run Code Online (Sandbox Code Playgroud)

让我们从顶部开始.flagWeekEnds并且flagHolidays都是纯粹的.情况1.

flagHolidays . flagWeekEnds
  :: a -> c
Run Code Online (Sandbox Code Playgroud)

这很纯粹.接下来是flagScheduled,这是monadic.案例2.

flagScheduled . flagHolidays . flagWeekEnds
  :: a -> m d
Run Code Online (Sandbox Code Playgroud)

接下来flagASAP,现在我们有两个monadic函数.案例3.

flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
  :: a -> m e
Run Code Online (Sandbox Code Playgroud)

最后,我们有纯粹的功能toWorkDays.案例4.

fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
  :: a -> m f
Run Code Online (Sandbox Code Playgroud)

我们已经完成了.


fuz*_*fuz 5

这不是很困难.你基本上只需更换(>>=)(.)和翻转操作数的顺序.do语法可能有助于澄清.我还使用Kleisli组合器(鱼)制作了示例pointfree (<=<) :: (b -> m c) -> (a -> m b) -> a -> m c,主要(.)用于monad.

import Control.Monad

flagWorkDays :: [C.Day] -> Handler [WorkDay] 
flagWorkDays =
  fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
Run Code Online (Sandbox Code Playgroud)

  • 来自Control.Arrow的@missingno`>>>` (虽然它有一个更通用的类型.) (5认同)

Tar*_*sch 5

要填写FUZxxl的答案,让我们简化flagWeekEnds:

flagWeekEnds :: [C.Day] -> [(C.Day,Availability)]
flagWeekEnds days = days `zip` map (flagAvailability . isWorkDay) days
Run Code Online (Sandbox Code Playgroud)

你经常在变量名(day- > days)之后加一个"s" 作为一个列表(就像你用英语复数一样).