Raf*_*ida 4 monads haskell functional-programming
我正在尝试学习haskell中的语句如何工作。我试图制作一个非常简单的程序,您可以在其中调用REST端点并执行系统命令(诸如“ ls”之类的非常简单的问题),问题在于将不同的动作类型组合在一个do语句中。
import Web.Scotty
import System.Cmd
main = do
putStrLn "Starting Server"
scotty 3000 $ do
get "/url" $ do
system "ls"
text "Success"
Run Code Online (Sandbox Code Playgroud)
但是我得到了下一个编译器错误:
Main.hs:12:7:
Couldn't match expected type ‘Web.Scotty.Internal.Types.ActionT
Data.Text.Internal.Lazy.Text IO a0’
with actual type ‘IO GHC.IO.Exception.ExitCode’
In a stmt of a 'do' block: system "ls"
In the second argument of ‘($)’, namely
‘do { system "ls";
text "Success" }’
Run Code Online (Sandbox Code Playgroud)
我很难学习Haskell!
In Haskell, do
-notation is used to chain statement-like things. A statement is some type constructor like IO
applied to a particular result type. For example, the statement system "ls"
has type IO ExitCode
.
Other type constructors other than IO
can work as statements. All that do
-notation requires is that the type constructor implements the Monad
interface which explains how to chain statements sensibly.
However, within a single do
-block, only one type of statement is allowed! They must be all IO
statements, or all ActionT Text IO
statements. In your example you are mixing the two, which causes the error. Scotty's get
function expects an ActionT Text IO
statement:
get :: RoutePattern -> ActionM () -> ScottyM ()
-- ActionM is actually a synonym for ActionT Text IO
Run Code Online (Sandbox Code Playgroud)
The good news is that there's a way to convert (the usual Haskell term is "lift") IO
statements into ActionT Text IO
statements. The latter are actually a kind of "decorator" (the usual Haskell term is "monad transformer") over IO
actions, which enable extra functionality related to Scotty. You can "lift" IO
actions into the decorator using the liftIO
function, like this:
get "/url" $ do
liftIO (system "ls")
text "Success"
Run Code Online (Sandbox Code Playgroud)
In general, when can we use liftIO
to lift a plain IO
statement into a "decorated" statement? The "decorator" type constructor must have a MonadIO
instance besides the usual Monad
instance. MonadIO
is what provides the liftIO
function.
In our case, looking at the available instances for ActionT
:
(MonadIO m, ScottyError e) => MonadIO (ActionT e m)
Run Code Online (Sandbox Code Playgroud)
Which means something like "if m
is has a MonadIO
instance—like IO
trivially does—and the error type e
has a ScottyError
instance—like Text
does—then we can lift IO
statements to ActionT e m
statements".
And the specialized type for liftIO
is:
liftIO :: IO a -> ActionT Text IO a
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
109 次 |
最近记录: |