如何将 Scotty 参数转换为字符串

How to convert Scotty parameter as String

我是 Haskell 的新手,正在使用 Scotty 网络库测试一些概念。

但是,我无法使简单的 hello world 页面正常工作。 我坚持将参数转换为字符串并应用于另一个函数。

这是尚未运行的高级代码。

{-# 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. return响应结果

我阅读并尝试过什么

我读过 Scotty doc and some code examples

我读到 paramParsable a => Text -> ActionM a 类型,ActionMActionT Text IO 类型。

我已经尝试了 name :: T.Text <- param "name"T.unpackliftIO 等,但没有成功。我想我没有完全理解这些类型。

问题

paramActionM 的类型到底是什么意思?

如何将参数提取为字符串以用于其他函数?

谢谢。

首先,一些工作代码:

{-# 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 monad 中,所以可以使用 let 绑定来代替 <- 语法。

param 可用于解析 Parseable 类型 class 的任何查询参数。

param :: Parsable a => Text -> ActionM a表示给定参数的文本名称,param可以返回任何你需要的类型,只要是Parseable。检查 the docs 以获取可用类型列表。请注意 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 类型的最后一个问题。

在幕后,ActionMActionT 的特殊形式:ActionM = ActionT Text IO

ActionT 表示在环境(http 请求)中发生的计算,可以修改内部状态(http 响应),并可能导致错误。它是使用一堆 monad 转换器制作的,如下所示:

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