2

我对如何正确使用回旋镖生成 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它的定义也可以,但不会。sitemaprState . stateRrPlace . (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)'
4

1 回答 1

1

类型看起来不同,因为您rPlace在行中使用状态需要比Router类型别名允许的更通用的类型签名。(你的代码很好。但也许我们应该在回旋镖中提供一个更通用的别名......)

如果删除 rPlace 行,则可以将 state 的类型签名更改为:

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

如果你更仔细地观察,我想你会看到这一点,state并且articleId实际上会朝着同一个方向发展。

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

的第三个参数xmaph指定如何解析一些底层值。在articleId它解析的情况下intstate它解析anyString.

的第一个参数xmaph指定如何将该值转换为所需的返回类型。在articleId我们简单地应用ArticleId构造函数。在state我们应用该read功能。但是在这两种情况下,我们都是从底层值到所需的返回类型:

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

的第二个参数xmaph指定如何将返回类型转换回基础值。

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

也就是说,我们实际上不应该在这里使用“读取”,因为“读取”可能会失败并出现错误。xmaph 的第一个参数是一个总函数。

我上传了 Boomerang 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.
于 2012-03-14T20:25:28.083 回答