веб-маршруты-бумеранг с простым алгебраическим типом данных - PullRequest
2 голосов
/ 14 марта 2012

Я немного запутался в том, как правильно использовать бумеранг для генерации URL. У меня есть следующее:

data State =
  AK | AL | AR | AZ | CA ... WY

data Sitemap
    = Home
    | State State
    | Place State String
      deriving (Eq, Ord, Read, Show, Data, Typeable)

$(derivePrinterParsers ''Sitemap)

sitemap ∷ Router Sitemap
sitemap =
    (  rHome
    <> rState . state
    <> rPlace . (state </> anyString)
    )

state :: PrinterParser StringsError [String] o (State :- o)
state = xmaph read (Just . show) anyString

Кажется, это работает, но когда я сравниваю мою реализацию state с той, что в документации для articleId, они, кажется, работают в противоположных направлениях:

articleId :: Router ArticleId
articleId = xmaph ArticleId (Just . unArticleId) int

Типы совершенно разные и выглядят так, как будто они движутся в противоположных направлениях, но мой sitemap работает и приложение правильно обрабатывает URL-адреса. Я думаю, это должно выглядеть примерно так:

maybeState :: String → Maybe State
maybeState stateString = case reads stateString of
                     [(state, "")] -> Just state
                     _             -> Nothing

stateR :: Router State
stateR = xpure show maybeState

Это не проверка типа, но даже замена undefined для его определения, в sitemap выше, rState . stateR будет работать, но rPlace . (stateR </> anyString) не будет.

Похоже, это будет происходить достаточно часто, возможно, есть библиотечная функция, которая позаботится обо мне, но я ее не видел.

Редактировать : вот некоторые из типов ошибок, которые я получаю:

Для state = xpure show maybeState:

Main.hs:56:16:
    Couldn't match expected type `State :- ()'
                with actual type `[Char]'
    Expected type: () -> State :- ()
      Actual type: () -> String
    In the first argument of `xpure', namely `show'
    In the expression: xpure show maybeState

Для state = undefined :: Router State (эта ошибка в определении sitemap):

Main.hs:45:18:
    Couldn't match expected type `String :- ()' with actual type `()'
    Expected type: PrinterParser
                     StringsError [String] () (State :- (String :- ()))
      Actual type: Router State
    In the first argument of `(</>)', namely `state'
    In the second argument of `(.)', namely `(state </> anyString)'

1 Ответ

1 голос
/ 15 марта 2012

Типы выглядят по-разному, поскольку для использования состояния в строке rPlace требуется более общая сигнатура типа, чем разрешает псевдоним типа Router.(Ваш код в порядке. Но, возможно, нам следует предложить более общий псевдоним в бумеранге ..)

Если вы удалите строку rPlace, вы можете изменить тип сигнатуры состояния на:

state :: Router State
state = xmaph read (Just . show) anyString

Если вы посмотрите более внимательно, я думаю, вы увидите, что state и articleId на самом деле идут в одном и том же направлении.

articleId :: Router ArticleId
articleId = xmaph ArticleId (Just . unArticleId) int

Третий аргумент xmaph указывает, как анализировать некоторые базовыезначение.В случае articleId он анализирует int, а для state он анализирует anyString.

Первый аргумент xmaph указывает, как преобразовать это значение в требуемый тип возвращаемого значения.В articleId мы просто применяем конструктор ArticleIdstate мы применяем функцию read.Но в обоих случаях мы переходим от базового значения к желаемому типу возвращаемого значения:

ArticleId :: Int    -> ArticleId
read      :: String -> State

Второй аргумент в xmaph указывает, как преобразовать возвращаемый тип обратно в базовое значение.

show        :: State     -> String
unArticleId :: ArticleId -> Int

Тем не менее, в любом случае мы не должны использовать здесь «чтение», потому что «чтение» может привести к ошибке и из-за ошибки.Предполагается, что первым аргументом xmaph будет общая функция.

Я загрузил бумеранг 1.3.1, который добавляет новый комбинатор в модуль Strings с именем readshow.Эта функция правильно использует экземпляры Read и Show.К сожалению, сообщения об ошибках немного неаккуратны, так как, когда reads терпит неудачу, он ничего не говорит нам о том, почему или где произошла ошибка.Но это лучше, чем ничего:)

Используя это, вы теперь можете написать:

state :: PrinterParser StringsError [String] o (State :- o)
state = readshow

, если мы предоставим недопустимое состояние, мы теперь получим:

> parseStrings sitemap ["AZ"]
Right (State AZ)
> parseStrings sitemap ["FOEU"]
Left parse error at (0, 0): unexpected FOEU; decoding using 'read' failed.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...