2011-06-22 17 views
9

如何使用消化函子創建一個具有編程生成的複選框列表的表單,該列表將返回一個列表。例如:帶消化函數的複選框列表

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

將返回["Milk", "Ground meat"]

我期待的類型會是這樣的:

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

回答

14

有這樣做沒有標準方法,但digestive-functors是高度可組合使用Applicative界面,讓您可以輕鬆地創建你想要的東西。

您可以定義一個checkBox,它返回Maybe String,即元素的名稱(如果已被選中)。

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 

然後,您可以遍歷字符串列表來創建這樣一個複選框列表中的每個元素:

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]可以幫助你減少的結果進一步:

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

最後,我們可以實例化實際的表格:

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

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

這很巧妙。謝謝 – Masse

+0

'listForm''可以使用'Data.Traversable'作爲'listForm'=遍歷checkBox'來更簡單地編寫。 – hammar