2011-11-22 25 views
16

Tôi đã quyết định hôm nay là ngày tôi sửa một số chức năng thuần túy đang chạy không cần thiết trong một hành động đơn thuần. Đây là những gì tôi có.Làm cách nào để tổ chức các chức năng thuần túy với các hành động đơn thuần của tôi theo cách tự động

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

Đây là flagWeekEnds, tính đến thời điểm hiện tại.

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 theo một mẫu tương tự. toWorkDays chỉ thay đổi loại này sang loại khác và là hàm thuần túy.

flagScheduledflagASAP là các hành động đơn thuần. Tôi không chắc chắn làm thế nào để kết hợp các hành động monadic với các chức năng tinh khiết idiomatically trong flagWorkDays. Ai đó có thể giúp tôi sửa chữa flagWorkDays, giả sử flagWeekEndsflagHolidays đã được thực hiện tinh khiết không?

Trả lời

28

Hãy lùi lại một chút. Bạn có hai loại hàm, một số loại thuần túy với các loại biểu mẫu a -> b và một số kiểu đơn lẻ là loại a -> m b.

Để tránh nhầm lẫn, chúng ta hãy gắn kết với bố cục từ phải sang trái. Nếu bạn muốn đọc từ trái sang phải, chỉ cần đảo ngược thứ tự của các hàm và thay thế (<=<) bằng (>=>)(.) với (>>>) từ Control.Arrow.

Sau đó, có bốn khả năng để làm thế nào chúng có thể được sáng tác.

  1. Tinh khiết sau đó thuần túy. Sử dụng chế độ chức năng thông thường (.).

    g :: a -> b 
    f :: b -> c 
    f . g :: a -> c 
    
  2. tinh khiết sau đó monadic. Cũng sử dụng (.).

    g :: a -> b 
    f :: b -> m c 
    f . g :: a -> m c 
    
  3. monadic sau đó monadic. Sử dụng thành phần kleisli (<=<).

    g :: a -> m b 
    f :: b -> m c 
    f <=< g :: a -> m c 
    
  4. monadic sau đó tinh khiết. Sử dụng fmap trên chức năng thuần túy và (.) để soạn.

    g :: a -> m b 
    f :: b -> c 
    fmap f . g :: a -> m c 
    

Bỏ qua những chi tiết cụ thể của các loại liên quan, chức năng của mình là:

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

Hãy đi từ trên xuống. flagWeekEndsflagHolidays đều thuần khiết. Case 1.

flagHolidays . flagWeekEnds 
    :: a -> c 

Điều này là tinh khiết. Tiếp theo là flagScheduled, đó là monadic. Trường hợp 2.

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

Tiếp theo là flagASAP, bây giờ chúng tôi có hai chức năng đơn điệu. Case 3.

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

Và cuối cùng, chúng tôi có chức năng thuần túy toWorkDays. Trường hợp 4.

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

Và chúng tôi đã hoàn tất.

+2

+1 cho lời giải thích chung – fuz

+3

Rực rỡ, như mọi khi. – Ingo

5

Nó không phải là rất khó khăn. Về cơ bản, bạn chỉ cần thay thế (>>=) theo (.) và lật thứ tự toán hạng. Cú pháp do có thể giúp làm rõ. Tôi cũng làm ví dụ điển hình bằng cách sử dụng bộ tổ hợp Kleisli (cá) (<=<) :: (b -> m c) -> (a -> m b) -> a -> m c, về cơ bản là (.) cho các đơn vị.

import Control.Monad 

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

Còn về 'dayList' thì sao? – Tarrasch

+0

@Tarrasch pointless'd away. Tôi quên xóa thông số bổ sung – fuz

+0

Có tên/hàm được xác định trước thông thường cho 'lật (.)' Không? Tôi hơi buồn vì sự biến đổi ở đây phải đặt mọi thứ về phía sau – hugomg

5

Để điền vào câu trả lời FUZxxl của, chúng ta hãy pureify flagWeekEnds:

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

Bạn thường đặt dấu "s" sau tên biến (day ->days) khi một danh sách của nó (như bạn làm với số nhiều bằng tiếng Anh).

Các vấn đề liên quan