如何将yesod-form参数解析为Haskell值

时间:2017-05-26 18:30:51

标签: haskell yesod yesod-forms

以下代码来自yesod-simple scaffold创建的Home.hs文件。 我喜欢在文本输入上进行简单的字符串操作,但不知道如何将其解析为Text值。 例如,我如何在fileDescription上使用toUpper? 我尝试过使用lookupPostParam 但我正在努力使用它的类型签名:

module Handler.Home where

import Import
import Yesod.Form.Bootstrap3 (BootstrapFormLayout (..), renderBootstrap3)
import Text.Julius (RawJS (..))

data FileForm = FileForm
    { fileInfo :: FileInfo
    , fileDescription :: Text
    }

getHomeR :: Handler Html
getHomeR = do
    (formWidget, formEnctype) <- generateFormPost sampleForm
    let submission = Nothing :: Maybe FileForm
        handlerName = "getHomeR" :: Text
    defaultLayout $ do
        let (commentFormId, commentTextareaId, commentListId) = commentIds
        aDomId <- newIdent
        setTitle "Welcome To Yesod!"
        $(widgetFile "homepage")

postHomeR :: Handler Html
postHomeR = do
    ((result, formWidget), formEnctype) <- runFormPost sampleForm
    let handlerName = "postHomeR" :: Text
        submission = case result of
            FormSuccess res -> Just res
            _ -> Nothing

    defaultLayout $ do
        let (commentFormId, commentTextareaId, commentListId) = commentIds
        aDomId <- newIdent
        setTitle "Welcome To Yesod!"
        $(widgetFile "homepage")

sampleForm :: Form FileForm
sampleForm = renderBootstrap3 BootstrapBasicForm $ FileForm
    <$> fileAFormReq "Choose a file"
    <*> areq textField textSettings Nothing
    where textSettings = FieldSettings
            { fsLabel = "What's on the file?"
            , fsTooltip = Nothing
            , fsId = Nothing
            , fsName = Nothing
                 , fsAttrs =
                    [ ("class", "form-control")
                    , ("placeholder", "File description")
                    ]
            }

commentIds :: (Text, Text, Text)
commentIds = ("js-commentForm", "js-createCommentTextarea", "js-
commentList")

Home.hs

import { Directive, Input, HostListener } from '@angular/core';
@Directive({
  selector: '[limitTo]'
})
export class LimitToDirective {
  @Input() limit: number;

  constructor() {

  }

  @HostListener("keypress", ["$event"])
  onkeypress(event) {
    if (event.target.value.length === this.limit) {
      event.preventDefault();
    }
  }
}

1 个答案:

答案 0 :(得分:1)

遗憾的是,这是文档和沟通方面的错误。

鉴于

lookupPostParam :: (MonadResource m, MonadHandler m) => Text -> m (Maybe Text)

读者可以推断m不仅是MonadResouceMonadHandler,还有Monad。这一小段代码将很多意图包含在一个非常小的句子中; Haskell库的大量使用是隐含的和潜在的,这是一个疣。例如,要在此类型的toUpper内调用Text,您就是这样做的:

{-# language OverloadedStrings #-}
foo :: (MonadResource m, MonadHandler m) => m (Maybe Text)
foo = do
  valueMaybe <- lookupPostParam "key"
  case valueMaybe of
    Just value ->
      pure (toUpper value)
    Nothing ->
      Nothing

请注意,monad堆栈(MonadHandlerMonadResource)已“感染”了您的代码。这是故意的,以便通过类型检查器限制您只在预期的Yesod环境/状态机/上下文/中运行此函数。

然而

您使用的是yesod-forms,在该框架内执行相同的操作会很不错。与lookupPostParam一样,我们可以利用monad-applicative-functor类型类。

我们可以根据您的Form FileForm值进行调整。

sampleForm :: AForm Handler FileForm
sampleForm =
  FileForm <$> fileAFormReq "Choose a file"
           <*> (toUpper <$> areq textField textSettings Nothing)

我认为版本之间yesod-forms的类型发生了变化。我在写作时将我的类型从最新版本复制到1.4.11。

这里我们利用Monad m => Functor (AForm m)实例。知道我们确实在monad(Handler monad)中意味着我们可以使用fmap及其不相关的兄弟<$>areq textField textSettings Nothing返回的值。这允许我们将Text上的任意函数提升到AForm m堆栈中。例如,我们从Text -> Text转到AForm Handler Text -> AForm Handler Text

希望有所帮助。