如何将Scotty参数转换为String

时间:2018-08-25 17:48:32

标签: haskell scotty

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

但是,我无法获得一个简单的hello world页面。 我一直坚持将参数转换为String并应用于另一个函数。

这是尚无法使用的高级代码。

{-# 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. 将结果作为响应返回

我阅读并尝试过什么

我已经阅读了Scotty doc和一些code examples

我了解到param的类型为Parsable a => Text -> ActionM a,而ActionM的类型为ActionT Text IO

我尝试了name :: T.Text <- param "name"T.unpackliftIO等,但是没有运气。我想我不太了解这些类型。

问题

paramActionM的类型实际上是什么意思?

如何将参数提取为String以便与其他函数一起使用?

谢谢。

1 个答案:

答案 0 :(得分:2)

首先,一些有效的代码:

{-# 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类型类的任何查询参数。

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++相同的功能,但是功能更通用,可以与所有monoid一起使用,而不仅仅是列表。

您最后一个有关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 }