减少 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"
]
看来 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"
]
是否有正确的方法来执行此操作(或者更好的是,拉出整个 ok $ "You did a "
and " .\n"
),还是根本不可能?
我仍在了解 monad 在 Haskell 中的工作原理,但如果上述情况不可能,那么您能否从高层次上解释一下为什么没有合理的方法来使其工作,或者需要更改哪些内容才能正常工作让它成为可能?我只是想弄清楚这里可以做什么和不能做什么。
The happstack tutorial provides the following sample:
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"
]
It seems that ok $
is redundant here -- is there any way of pulling that out of msum
so that you don't have to write ok $
three times? I tried the following, but it doesn't even compile:
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"
]
Is there a correct way to do this (or even better, pulling out the entirety of ok $ "You did a "
and ".\n"
), or is it just not possible?
I'm still getting up to speed on how monads work in Haskell, but if the above is not possible, then can you explain from a high level why there's no reasonable way to make this work, or what would need to be changed in order to allow it to be possible? I'm just trying to wrap my head around what can and cannot be done here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
ok
并不是真正多余。让我们仔细看看其中一个 do 块。我们将第一个 do 块拆分为一个名为
getPart
的单独函数。因此,我们清楚地看到我们正在使用
ServerPart
monad。因此,do 块中的每一行都必须具有类似ServerPart a
的类型。编写这样的代码不会工作:
因为 do 块中的最后一行的类型为
String
而不是 requireServerPart String
。将String
转换为ServerPart String
的典型方法是使用return
:请记住
return
的类型为:但是,当然,这并不比我们以前的情况好多少。我们没有
ok
,而是return
。确实没有办法避免这种“样板”。您需要一个ServerPart String
而不是String
,这意味着应用诸如return
或ok
之类的函数来完成提升。正如您所注意到的,消息的“You did a”部分是多余的。我们可以通过多种方式来解决这个问题。我们可以让处理程序只返回消息中不同的部分,如下所示:
然后我们可以获得
String
并添加消息的其余部分:(这可以更紧凑地表达,但我我的目标是提高可读性)。
该解决方案的一个问题是它迫使所有这些处理程序都符合完全相同的模具。如果我们想添加一个返回不符合该模式的消息的处理程序,我们就会遇到麻烦。另一种选择是创建一个简单的辅助函数来封装该模式:
希望这有帮助!
The
ok
is not really redundant.Let's look at one of the do blocks up close. We will split the first do-block out into a separate function named
getPart
.So, we see clearly that we are working with the
ServerPart
monad. Therefore every line in the do block must have a type likeServerPart a
.Writing something like this won't work:
because the last line in that do block has the type
String
not the requireServerPart String
. The typical way to convert aString
toServerPart String
is by usingreturn
:Remember that
return
has the type:But, of course, that is not any better than what we had before. Instead of
ok
we havereturn
. There is really no way to avoid that 'boilerplate'. You need aServerPart String
not aString
and that means applying a function likereturn
orok
to do the lifting.As you note, the
"You did a "
part of the message is redundant. There are several ways we could deal with that. We could have the handlers just return the part of the message that is different like this:And then we can get that
String
and add the rest of the message:(This can be expressed more compactly, but I am aiming for readability here).
One problem with that solution is that it forces all those handlers to conform to the exact same mold. If we wanted to add a handler that returned a message that did not fit that pattern, we would be in trouble. Another option would be to create a simple helper function that encapsulates that pattern:
Hope this helps!
不确定 dir 的类型,但类似这样的东西应该可以工作:
对于如此短的块,我很想撤消它们:
Not sure about the type of
dir
, but something like this should work:With such short blocks, I'd be tempted to un-do them: