Как я могу организовывать свои чистые функции с моими монадическими действиями идиоматически - программирование
Подтвердить что ты не робот

Как я могу организовывать свои чистые функции с моими монадическими действиями идиоматически

Сегодня я решил, что я исправлю некоторые из моих чистых функций, которые излишне выполняются в монадическом действии. Вот что у меня есть.

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

Вот флагWeekEnds, на данный момент.

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 являются монадическими действиями. Я не уверен, как объединить монадические действия с чистыми функциями идиоматически в flagWorkDays. Может ли кто-нибудь помочь мне исправить flagWorkDays, если flagWeekEnds и flagHolidays были сделаны чистыми?

4b9b3361

Ответ 1

Позвольте сделать шаг назад на мгновение. У вас есть два типа функций, некоторые чистые с типами формы a -> b и некоторые монадические типа a -> m b.

Чтобы избежать путаницы, давайте также придерживаться композиции справа налево. Если вы предпочитаете читать слева направо, просто измените порядок функций и замените (<=<) на (>=>) и (.) на (>>>) от Control.Arrow.

Есть четыре возможности для их компоновки.

  • Чистый, чистый. Используйте регулярную композицию функций (.).

     g :: a -> b
     f :: b -> c
     f . g :: a -> c
    
  • Чистый, затем монадический. Также используйте (.).

     g :: a -> b
     f :: b -> m c
     f . g :: a -> m c
    
  • Монадический, затем монадический. Используйте композицию kleisli (<=<).

     g :: a -> m b
     f :: b -> m c
     f <=< g :: a -> m c
    
  • Монадический, тогда чистый. Используйте 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, который является монадическим. Случай 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

И все готово.

Ответ 2

Это не очень сложно. Вы просто замените (>>=) на (.) и переверните порядок операндов. Синтаксис do может помочь прояснить. Я также сделал пример без использования комбинатора Клейсли (рыбы) (<=<) :: (b -> m c) -> (a -> m b) -> a -> m c, который по существу является (.) для монад.

import Control.Monad

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

Ответ 3

Чтобы заполнить ответ FUZxxl, пусть pureify flagWeekEnds:

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

Вы часто ставите "s" после имен переменных (daydays), когда его список (как вы делаете с множественным числом на английском языке).