在Yesod中可以使用Form Field转换吗?

时间:2012-06-28 17:24:32

标签: haskell yesod

是否可以为checkM提供以下类型:

checkM :: RenderMessage master msg => 
          (a -> GHandler sub master (Either msg b)) -> 
          Field sub master a -> Field sub master b

原因如下:

我有一个要求输入用户名的表单。使用checkM,我立即在数据库中查找输入的用户是否存在:

userField = checkM userexists textField
userexists input = do
  mbuser <- runDB $ getBy $ UniqueName input
  return $ case mbuser of
    Nothing  -> Left ("This user does not exist!" :: Text)
    (Just (Entity uid _)) -> Right input 
    -- I would like to write "return Right uid" above!

但是,我只能返回input :: Text,所以在表单接受用户输入之后,我需要为同一个名称执行另一个数据库查找以获取该用户的数据库密钥,这就是我的真实内容想要的。

(这个例子很大程度上简化了。基本上,我想获取一系列不同用户输入的数据库密钥(全部采用一种形式),我只能问它是否为TextFields?)

1 个答案:

答案 0 :(得分:3)

类型签名看起来是这样的原因是Field有两个方面:你如何解析它,以及如何渲染它。 checkM仅更改解析字段的方式,但呈现函数(fieldView)保持不变。因此,值需要保持相同的类型。

我能想到获得所需行为的最简单方法是使用一个函数,该函数可以从新类型的值中获取旧类型的值。这样,给定一个新值,我们可以将该函数应用于它并获取旧值以进行渲染。这是代码的样子:

checkM' :: RenderMessage master msg
        => (a -> GHandler sub master (Either msg b))
        -> (b -> a)
        -> Field sub master a
        -> Field sub master b
checkM' f inv field = field
    { fieldParse = \ts -> do
        e1 <- fieldParse field ts
        case e1 of
            Left msg -> return $ Left msg
            Right Nothing -> return $ Right Nothing
            Right (Just a) -> fmap (either (Left . SomeMessage) (Right . Just)) $ f a
    , fieldView = \i n a eres req -> fieldView field i n a (fmap inv eres) req
    }

因此,在您的情况下,您可以通过将userexists中的最后一行更改为:

来使用它
(Just (Entity uid _)) -> Right (input, uid)

然后将userField定义为

userField = checkM' userexists fst textField

我认为像checkM这样的函数有意义包含在yesod-form中,但希望有更好的名称;)。