我如何以惯用的方式组织我的纯函数和我的单子行为

发布于 2024-12-17 15:51:04 字数 873 浏览 1 评论 0原文

我决定今天是修复一些在单子操作中不必要运行的纯函数的日子。这就是我所拥有的。

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 中将单子操作与纯函数惯用地结合起来。假设 flagWeekEndsflagHolidays 已变得纯净,有人可以帮我修复 flagWorkDays 吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无边思念无边月 2024-12-24 15:51:04

让我们退后一步。您有两种类型的函数,其中一些是纯函数,其类型为 a ->; b,以及一些 a -> 类型的单子m b

为了避免混淆,我们也坚持从右到左的构图。如果您喜欢从左到右阅读,只需颠倒函数的顺序并将 (<=<) 替换为 (>=>),以及来自 Control.Arrow(.)(>>>)

那么如何组合它们有四种可能性。

  1. 纯粹再纯粹。使用常规函数组合(.)

    <代码> g :: a ->乙
     f::b-> c
     f. g::a-> c
    
  2. 纯粹然后一元。还可以使用 (.).

    <代码> g :: a ->乙
     f::b-> MC
     f. g::a-> MC
    
  3. 一元然后一元。使用 kleisli 组合(<=<)

    <代码> g :: a -> MB
     f::b-> MC
     f<=< g::a-> MC
    
  4. Monadic then pure。在纯函数上使用 fmap 并使用 (.) 进行组合。

    <代码> g :: a -> MB
     f::b-> c
     f 映射 f 。 g::a-> MC
    

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

flagWeekEnds :: a -> b
flagHolidays :: b -> c
flagScheduled :: c -> m d
flagASAP :: d -> m e
toWorkDays :: e -> f

让我们从顶部开始。 flagWeekEndsflagHolidays 都是纯的。情况1.

flagHolidays . flagWeekEnds
  :: a -> c

这是纯粹的。接下来是flagScheduled,它是一元的。情况 2.

flagScheduled . flagHolidays . flagWeekEnds
  :: a -> m d

接下来是 flagASAP,现在我们有两个一元函数。情况 3。

flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
  :: a -> m e

最后,我们有纯函数 toWorkDays。案例 4.

fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
  :: a -> m f

我们就完成了。

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.

  1. Pure then pure. Use regular function composition (.).

     g :: a -> b
     f :: b -> c
     f . g :: a -> c
    
  2. Pure then monadic. Also use (.).

     g :: a -> b
     f :: b -> m c
     f . g :: a -> m c
    
  3. Monadic then monadic. Use kleisli composition (<=<).

     g :: a -> m b
     f :: b -> m c
     f <=< g :: a -> m c
    
  4. 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.

痴意少年 2024-12-24 15:51:04

为了填写 FUZxxl 的答案,让我们纯化 flagWeekEnds

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

您经常在变量名称后放置一个“s”(day -> days)一个列表(就像英语中的复数形式一样)。

To fill in FUZxxl's answer, let's pureify flagWeekEnds:

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

You often put an "s" after variable names (day -> days) when its a list (as you do with plural in English).

栀子花开つ 2024-12-24 15:51:04

这不是很困难。您基本上只需将 (>>=) 替换为 (.) 并翻转操作数顺序即可。 do 语法可能有助于澄清。我还使用 Kleisli 组合器 (fish) (<=<) :: (b -> mc) -> 将示例设为 pointfree。 (a→mb)→一个-> m c,本质上是 monad 的 (.)

import Control.Monad

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

It's not very difficult. You basically just replace (>>=) by (.) and flip the operands order. do syntax may help to clarify. I also made the example pointfree using the Kleisli combinator (fish) (<=<) :: (b -> m c) -> (a -> m b) -> a -> m c, that is essentially (.) for monads.

import Control.Monad

flagWorkDays :: [C.Day] -> Handler [WorkDay] 
flagWorkDays =
  fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文