Как преобразовать параметр Скотти в строку - PullRequest
0 голосов
/ 25 августа 2018

Я новичок в Haskell и тестирую некоторые концепции в веб-библиотеке Scotty.

Тем не менее, я не могу заставить работать простую страницу приветствия. Я застрял при преобразовании параметра в строку и применить к другой функции.

Вот код высокого уровня, который еще не работает.

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Web.Scotty

main :: IO ()
main = scotty 3000 $
  get "/" $ do
    name <- param "name" `rescue` (\_ -> return "haskell")
    greeting <- hello name
    html $ concat ["<h1>hello ", greeting, "</h1>"]

hello :: String -> String
hello s = "hello " ++ s

Сообщения об ошибках

app/Main.hs:11:17: error:
    • Couldn't match type ‘[]’
                     with ‘Web.Scotty.Internal.Types.ActionT
                             Data.Text.Internal.Lazy.Text IO’
      Expected type: Web.Scotty.Internal.Types.ActionT
                       Data.Text.Internal.Lazy.Text IO Char
        Actual type: String
<Omitted>
   |
11 |     greeting <- hello name
   |                 ^^^^^^^^^^

app/Main.hs:12:12: error:
    • Couldn't match expected type ‘Data.Text.Internal.Lazy.Text’
                  with actual type ‘[Char]’
<Omitted>
   |
12 |     html $ concat ["<h1>hello ", greeting, "</h1>"]
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

app/Main.hs:12:34: error:
    • Couldn't match expected type ‘[Char]’ with actual type ‘Char’
<Omitted>
   |
12 |     html $ concat ["<h1>hello ", greeting, "</h1>"]
   |                                  ^^^^^^^^

Цель

Функция hello является заглушкой. Я хотел бы доказать, что работает следующий механизм.

  1. извлечь параметр в виде строки

  2. применяется к String -> String функции

  3. вернуть результат как ответ

Что я прочитал и попробовал

Я прочитал Скотти документ и некоторые примеры кода .

Я прочитал, что param имеет тип Parsable a => Text -> ActionM a, а ActionM имеет тип ActionT Text IO.

Я пробовал name :: T.Text <- param "name", T.unpack, liftIO и т. Д., Но не повезло. Я думаю, что я не понимаю типы полностью.

Вопросы

Что на самом деле означают типы для param и ActionM?

Как извлечь параметр в виде строки для использования с другими функциями?

Спасибо.

1 Ответ

0 голосов
/ 25 августа 2018

Сначала немного рабочего кода:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Data.Text.Lazy (Text)
import Web.Scotty

main :: IO ()
main = scotty 3000 $
  get "/" $ do
    name <- param "name" `rescue` (\_ -> return "haskell")
    let greeting = hello name
    html $ mconcat ["<h1>hello ", greeting, "</h1>"]

hello :: Text -> Text
hello s = "hello " <> s

Поскольку hello не входит в монаду ActionM, вместо синтаксиса <- может использоваться привязка let.

param может использоваться для анализа любого параметра запроса, относящегося к классу типа Parseable.

param :: Parsable a => Text -> ActionM a означает, что с учетом текстового имени параметра, param может вернуть любой тип, который вам нужен, если он Parseable. Проверьте документы для списка доступных типов. Обратите внимание, что String нет в этом списке, однако Text есть. Вот почему в приведенном выше коде я изменил функцию hello для работы с Text вместо String. Если вы предпочитаете использовать String, вы можете распаковать разобранный параметр как:

name <- T.unpack <$> param "name" `rescue` (\_ -> return "haskell")
let greeting = hello name -- where `hello :: String -> String`

(но тогда вам нужно будет упаковать результат в текст перед использованием функции html)

Другие необходимые изменения заменяли concat на mconcat и ++ на <>. Эти функции выполняют то же самое, что и concat и ++, но являются более общими и работают со всеми моноидами, а не только со списками.

Ваш последний вопрос о том, что означает тип ActionM.

Под капотом ActionM - это специализированная форма ActionT: ActionM = ActionT Text IO

ActionT представляет вычисление, которое выполняется в среде (запрос http), может изменить внутреннее состояние (ответ http) и может привести к ошибке. Он сделан с использованием стека монадных трансформаторов, который выглядит следующим образом:

newtype ActionT e m a = ActionT 
  { runAM :: ExceptT (ActionError e) (ReaderT ActionEnv (StateT ScottyResponse m)) a }
...