如何整理我的纯函数与我的单子行动惯用

问题描述:

今天我决定是一天我解决一些被不必要地在一元行动运行我的纯函数。这是我的。如何整理我的纯函数与我的单子行动惯用

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只是将一种类型更改为另一种类型,并且是一种纯粹的功能。

flagScheduledflagASAP是一元行动。我不知道如何在flagWorkDays中将monadic操作与纯函数惯用地结合起来。假设flagWeekEndsflagHolidays已经被做成纯的,有人能帮我修复flagWorkDays吗?

让我们退一步了一会儿。您有两种类型的功能,其中一些类型为a -> b,一些类型为a -> m b

为了避免混淆,我们还要坚持从右到左的组合。如果你喜欢阅读左到右,只是反转的功能的顺序和Control.Arrow(>>>)取代(<=<)(>=>)(.)

有那么对于如何将这些由四种可能性。

  1. 纯则纯。使用常规功能组合(.)

    g :: a -> b 
    f :: b -> c 
    f . g :: a -> c 
    
  2. 纯然后单子。也使用(.)

    g :: a -> b 
    f :: b -> m c 
    f . g :: a -> m c 
    
  3. 单子然后单子。使用kleisli组成(<=<)

    g :: a -> m b 
    f :: b -> m c 
    f <=< g :: a -> m c 
    
  4. 单子然后纯。在纯功能上使用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 

让我们从上面走。 flagWeekEndsflagHolidays都是纯的。案例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 

我们完成了。

+2

+1一般说明 – fuz

+3

一如既往的辉煌。 – Ingo

这不是很困难的。您基本上只需将(>>=)替换为(.)并翻转操作数顺序。语法可能有助于澄清。我也使用Kleisli combinator(鱼)(<=<) :: (b -> m c) -> (a -> m b) -> a -> m c,这基本上是(.)单子的例子pointfree。

import Control.Monad 

flagWorkDays :: [C.Day] -> Handler [WorkDay] 
flagWorkDays = 
    fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds 
+0

'dayList'呢? – Tarrasch

+0

@Tarrasch毫无意义地离开了。我忘了删除额外的参数 – fuz

+0

“flip(。)”是否有通常的名称/预定义函数?我有点难过,在这里的变革必须倒退 – hugomg

为了填补FUZxxl的回答,让我们pureify flagWeekEnds

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

你经常把一个 “s” 变量名之后(day - >days)时,其列表(如你有多个办用英语)。