There is no standard way to do so, but digestive-functors
is highly composable using the Applicative
interface, so you can easily create what you want.
You can define a checkBox
which returns a Maybe String
, i.e. the name of the element if it was checked.
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
You can then loop over a list of strings to create a checkbox like this for each element in the list:
listForm' :: (Functor m, Monad m)
=> [String]
-> HappstackForm m Html BlazeFormHtml [Maybe String]
listForm' = foldr (\x xs -> fmap (:) x <*> xs) (pure []) . map checkBox
The catMaybes :: [Maybe a] -> [a]
helps you to reduce the result further:
listForm :: (Functor m, Monad m)
=> [String]
-> HappstackForm m Html BlazeFormHtml [String]
listForm = fmap catMaybes . listForm'
And finally, we can instantiate the actual form:
food :: [String]
food = ["Milk", "Cereals", "Ground meat"]
foodForm :: (Functor m, Monad m)
=> HappstackForm m Html BlazeFormHtml [String]
foodForm = listForm food
listForm'
can be written more simply usingData.Traversable
aslistForm' = traverse checkBox
. – Touchy