Search code examples
haskellhaskell-snap-frameworkdigestive-functors

Digestive-functors and listOf


I've been able to use digestive-functors with simple forms successfully in a snap application; however, I'm getting stuck when trying to handle a list of hidden inputs. There is something I'm not quite getting on how to use listOf. Can anyone point me in the right direction? Thanks.

The rendered html from a previous page includes the following hidden fields:

<div id='messageForm.recipients' class='inputList'>
  <input type='hidden' name='messageForm.recipients.indices' value='0' />
  <input type='hidden' id='messageForm.recipients.-1.email' name='messageForm.recipients.-1.email' value />
  <input type='hidden' id='messageForm.recipients.0.email' name='messageForm.recipients.0.email' value='[email protected]' /> 
  <input type='hidden' id='messageForm.recipients.1.email' name='messageForm.recipients.1.email' value='[email protected]' /> 
</div>

The data types are:

data ConfirmMessage = ConfirmMessage {
  isoDate :: T.Text,
  subject :: T.Text,
  body    :: T.Text,
  action  :: T.Text,
  recipients :: [Recipient]
} deriving (Show) 

data Recipient = Recipient {
  email :: T.Text 
} deriving (Show)

The forms are:

messageForm :: (Monad m) => Form T.Text m ConfirmMessage
messageForm = ConfirmMessage
  <$> "isoDate"    .: stringRead "Missing ISOdate" Nothing
  <*> "subject"    .: stringRead "Subject required" Nothing
  <*> "body"       .: stringRead "Body required" Nothing
  <*> "action"     .: stringRead "Missing action" Nothing
  <*> "recipients" .: listOf recipientForm' Nothing

recipientForm' :: (Monad m) => Formlet T.Text m Recipient
recipientForm'= Recipient
  <$> "email"      .: text Nothing

The error message I am getting is:

Couldn't match type `Text.Digestive.Form.Internal.FormTree
                       m0 v0 m0 Recipient'
              with `Maybe Recipient -> Form T.Text m Recipient'
Expected type: Formlet T.Text m Recipient
  Actual type: Text.Digestive.Form.Internal.FormTree
                 m0 v0 m0 Recipient
Relevant bindings include
  recipientForm' :: Formlet T.Text m Recipient
    (bound at src/Handler/TradeNotifyConfirm.hs:191:1)
In the expression: Recipient <$> "email" .: text Nothing
In an equation for `recipientForm'':
    recipientForm' = Recipient <$> "email" .: text Nothing

Solution

  • Okay disclaimer: I have never used digestive-functors, but here is how I approach this kind of problem:

    1) Your error message says Expected type: Formlet T.Text m Recipient and Actual type: Text.Digestive.Form.Internal.FormTree m0 v0 m0 Recipient

    2) Look at the documentation and see that:

    type Formlet v m a = Maybe a -> Form v m a 
    type Form v m a = FormTree m v m a
    

    so we expand the expected from above to get:

    Formlet T.Text m Recipient 
    -- v ~ T.Text, a ~ Recipient
    Maybe Recipient -> Form T.Text m Recipient
    --
    Maybe Recipient -> FormTree m T.Text m Recipient
    

    now look again:

    • Expected type: Maybe Recipient -> FormTree m T.Text m Recipient
    • Actual type: FormTree m0 v0 m0 Recipient

    We are missing a Maybe Recipient! From what I see above I guess you want to just ignore that argument and therefore we have:

    recipientForm' :: (Monad m) => Formlet T.Text m Recipient
    recipientForm' _ = Recipient <$> "email" .: text Nothing
    

    which compiles just fine, yay :)