Сначала немного рабочего кода:
{-# 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 }