2011-06-22 24 views
9

Jak używać funktorów trawiennych do utworzenia formularza, który ma wygenerowaną programowo listę pól wyboru, które zwrócą listę. Na przykład:Lista pól z funktorami trawiennymi

[x] Milk 
[ ] Cereals 
[x] Ground meat 

wróci ["Milk", "Ground meat"].

Czekam typ byłoby coś takiego:

form :: (Functor m, Monad m) => [String] -> HappstackForm m Html BlazeFormHtml [String] 

Odpowiedz

14

nie ma standardowego sposobu, aby to zrobić, ale jest wysoce digestive-functors composable pomocą interfejsu Applicative, dzięki czemu można łatwo tworzyć, co chcesz.

Można zdefiniować wartość checkBox, która zwraca wartość Maybe String, tj. Nazwę elementu, jeśli została zaznaczona.

checkBox :: (Functor m, Monad m) 
     => String -> HappstackForm m Html BlazeFormHtml (Maybe String) 
checkBox str = fmap maybeStr (inputCheckBox False) <++ label str 
    where 
    maybeStr True = Just str 
    maybeStr False = Nothing 

Można następnie pętli nad listą ciągów stworzyć wyboru takiego dla każdego elementu w liście:

listForm' :: (Functor m, Monad m) 
      => [String] 
      -> HappstackForm m Html BlazeFormHtml [Maybe String] 
listForm' = foldr (\x xs -> fmap (:) x <*> xs) (pure []) . map checkBox 

catMaybes :: [Maybe a] -> [a] pomaga zmniejszyć efekt dalej:

listForm :: (Functor m, Monad m) 
     => [String] 
     -> HappstackForm m Html BlazeFormHtml [String] 
listForm = fmap catMaybes . listForm' 

I na koniec możemy utworzyć konkretny formularz:

food :: [String] 
food = ["Milk", "Cereals", "Ground meat"] 

foodForm :: (Functor m, Monad m) 
     => HappstackForm m Html BlazeFormHtml [String] 
foodForm = listForm food 
+0

To genialne. Dziękuję – Masse

+0

'listForm'' można napisać po prostu używając' Data.Traversable' jako 'listForm '= traverse checkBox'. – hammar