我是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
函数是一个存根。我想证明以下机制有效。
将参数提取为字符串
应用于String -> String
函数
将结果作为响应返回
我已经阅读了Scotty doc和一些code examples。
我了解到param
的类型为Parsable a => Text -> ActionM a
,而ActionM
的类型为ActionT Text IO
。
我尝试了name :: T.Text <- param "name"
,T.unpack
,liftIO
等,但是没有运气。我想我不太了解这些类型。
param
和ActionM
的类型实际上是什么意思?
如何将参数提取为String以便与其他函数一起使用?
谢谢。
答案 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
类型的含义的问题。
在幕后,ActionM
是ActionT
的一种特殊形式:ActionM = ActionT Text IO
ActionT
表示在环境(http请求)中进行的,可修改内部状态(http响应)并可能导致错误的计算。它是使用一堆看起来像这样的monad变压器制成的:
newtype ActionT e m a = ActionT
{ runAM :: ExceptT (ActionError e) (ReaderT ActionEnv (StateT ScottyResponse m)) a }