减少happstack教程代码中的冗余

Dax*_*ohl 3 haskell happstack

happstack教程提供以下示例:

main :: IO ()
main = simpleHTTP nullConf $ msum 
       [ do methodM GET
            ok $ "You did a GET request.\n"
       , do methodM POST
            ok $ "You did a POST request.\n"
       , dir "foo" $ do methodM GET
                        ok $ "You did a GET request on /foo.\n"
       ]
Run Code Online (Sandbox Code Playgroud)

这似乎ok $是多余的 - 有没有办法把它拉出来,msum这样你就不必写ok $三次了?我尝试了以下,但它甚至没有编译:

main :: IO ()
main = simpleHTTP nullConf $ ok $ msum 
       [ do methodM GET
            "You did a GET request.\n"
       , do methodM POST
            "You did a POST request.\n"
       , dir "foo" $ do methodM GET
                        "You did a GET request on /foo.\n"
       ]
Run Code Online (Sandbox Code Playgroud)

有没有正确的方法来做到这一点(甚至更好,拉出整个ok $ "You did a "".\n"),还是只是不可能?

我还在快速了解monads如何在Haskell中工作,但是如果上述情况不可能,那么你能从高层解释为什么没有合理的方法来完成这项工作,或者需要按顺序改变什么允许它可能吗?我只是想绕过这里可以做什么和不能做什么.

ste*_*cut 5

ok并不是多余的.

让我们看看其中一个关闭的阻滞.我们将第一个do-block拆分为一个名为的单独函数getPart.

getPart :: ServerPart String
getPart = do methodM GET
             ok $ "You did a GET request.\n"
Run Code Online (Sandbox Code Playgroud)

所以,我们清楚地看到我们正在与ServerPartmonad合作.因此do块中的每一行都必须具有类似的类型ServerPart a.

写这样的东西是行不通的:

getPart :: ServerPart String
getPart = do methodM GET
             "You did a GET request.\n"
Run Code Online (Sandbox Code Playgroud)

因为该块中的最后一行的类型String不是require ServerPart String.转换一个典型的方法StringServerPart String是使用return:

getPart :: ServerPart String
getPart = do methodM GET
             return "You did a GET request.\n"
Run Code Online (Sandbox Code Playgroud)

请记住,return有类型:

return :: (Monad m) => a -> m a
Run Code Online (Sandbox Code Playgroud)

但是,当然,这并不比我们以前更好.而不是ok我们拥有return.实际上没有办法避免这种"样板".你需要一个ServerPart String不是a String,这意味着应用一个类似的功能returnok进行提升.

如您所知,"You did a "消息的一部分是多余的.我们有几种方法可以解决这个问题.我们可以让处理程序只返回不同的消息部分,如下所示:

handlers :: ServerPart String
handlers = 
       [ do methodM GET
            ok $ "GET request"
       , do methodM POST
            ok $ "POST request"
       , dir "foo" $ do methodM GET
                        ok $ "GET request on /foo"
       ]
Run Code Online (Sandbox Code Playgroud)

然后我们可以得到它String并添加其余的消息:

main :: IO ()
main = simpleHTTP nullConf $ do msg <- handlers
                                return ("You did a " ++ msg ++ ".\n")
Run Code Online (Sandbox Code Playgroud)

(这可以更紧凑地表达,但我的目标是可读性).

该解决方案的一个问题是它迫使所有那些处理者符合完全相同的模具.如果我们想添加一个返回不符合该模式的消息的处理程序,我们就会遇到麻烦.另一种选择是创建一个封装该模式的简单辅助函数:

methodMsg :: Method -> String -> ServerPart String
methodMsg mthd msg = do methodM mthd
                        ok $ "You did a " ++ msg ++ ".\n"

main :: IO ()
main = simpleHTTP nullConf $ msum 
       [ methodMsg GET  "GET request"
       , methodMsg POST "POST request"
       , dir "foo" $ methodMsg GET "GET request on /foo"
       -- the bar handler does not follow the pattern
       , dir "bar" $ ok $ "let's go to the bar!"
       ]
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!