Как преобразовать параметры формы yesod в значения Haskell

Приведенный ниже код взят из файла Home.hs, созданного скаффолдом yesod-simple. Мне нравится выполнять простые манипуляции со строками при вводе текста, но я не знаю, как преобразовать его в текстовое значение. Как, например, я могу использовать toUpper для описания файла? Я пытался использовать lookupPostParam, но я борюсь с его подписью типа:

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

Home.hs

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")

person Adrian V.    schedule 26.05.2017    source источник


Ответы (1)


К сожалению, это ошибка в документации и коммуникации.

Дано

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

читатель должен сделать вывод, что m - это не только MonadResouce и MonadHandler, но и 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

Обратите внимание, что стек монад (MonadHandler, MonadResource) "заразил" ваш код. Это должно быть преднамеренным, чтобы заставить вас через средство проверки типов запускать эту функцию только в предполагаемой среде/конечном автомате/контексте/независимо от 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) экземпляр. Знание того, что мы действительно находимся в монаде (монаде Handler), означает, что мы можем использовать fmap и его инфиксного брата <$> для значения, возвращаемого areq textField textSettings Nothing. Это позволяет нам поднимать произвольные функции, действующие на Text, в стек AForm m. Например, здесь мы перешли от Text -> Text к AForm Handler Text -> AForm Handler Text.

Надеюсь, это поможет.

person hao    schedule 28.05.2017
comment
Я скопировал тип lookupPostParam где-то в Интернете: в следующий раз я воспользуюсь для этого хакерским сайтом, но я не знаю, как найти версию yesod-form, которую я установил. Команда «stack exec -- версия yesod» возвращает yesod-bin 1.5.2.3. Установка осуществляется в соответствии с руководством по быстрому запуску в системе Ubuntu 16.04 LTS. Я попробовал ваши предложения, но все еще получаю ошибки «Не удалось сопоставить ожидаемый тип». Однако ваш ответ дал мне несколько советов, чтобы смотреть дальше, поэтому я нажал галочку. Спасибо! - person Adrian V.; 30.05.2017
comment
Я получил это от hackage.haskell.org/package/yesod-core-1.4.33/docs/ но я думаю, вы уже поняли это; чтобы узнать, какую версию пакета вы используете со стеком, попробуйте stack list-dependencies - person hao; 30.05.2017