如何根据另一个字段验证一个字段?

How can I validate a field based on another field?

我正在尝试使用 emailemailConfirmationpasswordpasswordConfirmation 等字段的注册表单。验证 emailpassword 很容易,有规则,我已经编写了相应的函数。

另外两个更难。我找到了这个 question 并尝试像这样编写我的代码:

表单定义,使用 Blaze:

registrationForm :: (View Html) -> Html
registrationForm view = docTypeHtml $ do
  form ! name "registration" ! method "post" ! action "/register" $ do
    fieldset $ do
      label ! for "password" $ (text "Password")
      inputText "password" view
      errorList "password" view

      br

      label ! for "passwordConfirmation" $ (text "Password Confirmation")
      inputText "passwordConfirmation" view
      errorList "passwordConfirmation" view

和验证器:

data Password = Password { password :: Text }

validateForm :: Monad m => Form Html m Password
validateForm =
  Password
    <$> "password" .: validatePassword
  where
    validatePassword =
      validate fst' $ (,) <$> ("password"             .: D.text Nothing)
                          <*> ("passwordConfirmation" .: D.text Nothing)
    fst' (p1, p2) | p1 == p2  = Success p1
                  | otherwise = Error "Passwords must match"

但是每当我 运行 服务器时,我都会收到一条消息说 "password is not a field"。如果我删除验证并给 password 一个简单的验证,那么它会按预期工作。我在这里遗漏了什么吗?

我在 digestive-functors 库上得到了帮助。 Thanks cimmanon

这是最终代码,注意字段名称现在是 "password.p1"/"password.p2" 而不是 password/passwordConfirmation.

registrationForm :: (View Html) -> Html
registrationForm view = docTypeHtml $ do
  form ! name "registration" ! method "post" ! action "/register" $ do
    fieldset $ do
      inputText "password.p1" view
      br
      inputText "password.p2" view
      errorList "password" view
data Password = Password { password :: Text }

验证器是一样的,除了新的名字:

validateForm :: Monad m => Form Html m Password
validateForm =
  Password
    <$> "password" .: validatePassword
  where
    validatePassword =
      validate fst' $ (,) <$> ("p1" .: D.text Nothing)
                          <*> ("p2" .: D.text Nothing)
    fst' (p1, p2) | p1 == p2  = Success p1
                  | otherwise = Error "Passwords must match"