前言:這顯然是要減少的,你上面貼的代碼量,但是從長遠來看,這可能使事情變得更容易維護,因爲它提供了進行驗證以一致的方式,並允許您處理強類型的對象而不是大量的文本值。
如果你打算做任何數量的表單處理,我會建議使用表單庫。我個人使用過digestive-functors,並且發現與它合作愉快。此外,它還配備了Happstack後端,使Happstack集成非常直觀。
這可能比您更關心的投資,但這裏是您的表單代碼可能看起來像使用消化函數的樣本。我沒有嘗試編譯這些,所以它可能會或可能不會工作,但希望它提供了總體思路。
{-# LANGUAGE OverloadedStrings #-}
module Forms where
import Control.Applicative ((<$>), (<*>))
import Data.Text (Text)
import qualified Data.Text as T
import Happstack.Server
import Text.Digestive
data AddressState
= Alabama
| Alaska
| Arkansas
-- ...
deriving (Enum, Eq, Read)
data Country
= Canada
| Mexico
| UnitedStates
-- ...
deriving (Enum, Eq, Read)
data Address = Address
{ street1 :: Text
, street2 :: Maybe Text
, suburb :: Maybe Text
, postcode :: Int
, state :: AddressState
, country :: Country
}
data ShippingForm = ShippingForm
{ deliveryAddress :: Address
, billingAddress :: Address
}
addressForm :: (Monad m) => Form Text m Address
addressForm = Address
<$> "street1" .: nonEmptyText (text Nothing)
<*> "street2" .: optionalText Nothing
<*> "suburb" .: optionalText Nothing
<*> "postcode" .: stringRead "Please enter a valid postcode" Nothing
<*> "state" .: choice mkChoices Nothing
<*> "country" .: choice mkChoices Nothing
where
nonEmptyText = check "Cannot be empty" (not . T.null)
mkChoices = [(x, T.pack (show x)) | x <- [minBound .. maxBound]]
shippingForm :: (Monad m) => Form Text m ShippingForm
shippingForm = ShippingForm
<$> "delivery" .: addressForm
<*> "billing" .: addressForm
formHandler :: ServerPart Response
formHandler = do
method POST
decodeBody $ defaultBodyPolicy "/tmp" 4096 4096 4096
res <- runForm "shipping" shippingForm
case res of
(view, Nothing) -> do
-- setup your view
ok $ toResponse() -- <-- replace this with your view code
(_, Just formData) -> do
-- here, formData is a fully valid `ShippingForm`
let delStreet1 = (street1 . deliveryAddress) formData
-- do whatever you need to with this data (ie: persist it to a database, etc)
ok $ toResponse()
有關消化仿函數的一些良好的閱讀,你可以看看下面的鏈接:
digestive functors tutorial
ocharles' blog post
'[A,B,C] < - MAPM一下[X ,y,z]'? – user2407038 2014-09-26 07:06:53