ok
на самом деле не является избыточным.
Давайте посмотрим на один из блоков до. Мы разделим первый do-блок на отдельную функцию с именем getPart
.
getPart :: ServerPart String
getPart = do methodM GET
ok $ "You did a GET request.\n"
Итак, мы ясно видим, что работаем с монадой ServerPart
. Поэтому каждая строка в блоке do должна иметь тип, подобный ServerPart a
.
Запись чего-то подобного не будет работать :
getPart :: ServerPart String
getPart = do methodM GET
"You did a GET request.\n"
потому что последняя строка в этом блоке do имеет тип String
, а не require ServerPart String
. Типичный способ конвертировать String
в ServerPart String
- использовать return
:
getPart :: ServerPart String
getPart = do methodM GET
return "You did a GET request.\n"
Помните, что return
имеет тип:
return :: (Monad m) => a -> m a
Но, конечно, это не лучше, чем у нас было раньше. Вместо ok
у нас есть return
. На самом деле нет никакого способа избежать этого «эталона». Вам нужен ServerPart String
, а не String
, а это означает применение функции, подобной return
или ok
, для подъема.
Как вы заметили, часть сообщения "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"
]
И тогда мы можем получить это String
и добавить остальную часть сообщения:
main :: IO ()
main = simpleHTTP nullConf $ do msg <- handlers
return ("You did a " ++ msg ++ ".\n")
(это можно выразить более компактно, но я стремлюсь к удобочитаемости здесь).
Одна из проблем этого решения заключается в том, что оно заставляет все эти обработчики соответствовать одной и той же форме. Если бы мы хотели добавить обработчик, который возвращал бы сообщение, которое не соответствовало этому шаблону, у нас были бы проблемы. Другой вариант - создать простую вспомогательную функцию, которая инкапсулирует этот шаблон:
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!"
]
Надеюсь, это поможет!