17

今日は、モナド アクションで不必要に実行されているいくつかの純粋な関数を修正する日だと決めました。これが私が持っているものです。

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はモナド アクションです。単項アクションと純粋な関数を慣用的に組み合わせる方法がわかりませんflagWorkDays。純粋にされたとflagWorkDays仮定して、flagWeekEnds誰かが私を修正するのを手伝ってくれますか?flagHolidays

4

3 に答える 3

29

少し前に戻りましょう。2つのタイプの関数があります。1つはフォームのタイプを持つ純粋な関数で、もう1つa -> bはタイプのモナディックですa -> m b

混乱を避けるために、右から左への構成にも固執しましょう。左から右に読みたい場合は、関数の順序を逆にして、、およびfromに置き換え(<=<)てください。(>=>)(.)(>>>)Control.Arrow

これらをどのように構成できるかについては、4つの可能性があります。

  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. モナディック、次にモナディック。クライスリ構成を使用します(<=<)

     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、モナディックです。ケース2。

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

次はflagASAP、2つのモナディック関数があります。ケース3。

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

そして最後に、純粋関数がありますtoWorkDays。ケース4。

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

これで完了です。

于 2011-11-22T22:41:00.313 に答える
5

それほど難しいことではありません。基本的には、オペランドの順序を置き換え(>>=)(.)反転するだけです。do構文は明確にするのに役立つ場合があります。(<=<) :: (b -> m c) -> (a -> m b) -> a -> m cまた、基本的(.)にモナド用である Kleisli コンビネータ (fish) を使用して、この例をポイントフリーにしました。

import Control.Monad

flagWorkDays :: [C.Day] -> Handler [WorkDay] 
flagWorkDays =
  fmap toWorkDays . flagASAP <=< flagScheduled . flagHolidays . flagWeekEnds
于 2011-11-22T21:53:57.020 に答える