具有简单代数数据类型的web-routes-boomerang

时间:2012-03-13 22:03:15

标签: haskell routes boomerang

关于如何正确使用回旋镖来生成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正常工作且应用正确处理了网址。我认为看起来应该更像这样:

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)不会。 / p>

看起来这样经常会出现,我可能会有一个库函数来处理这个问题,但是我没有看到它。

修改:以下是我遇到的一些类型错误:

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 个答案:

答案 0 :(得分:1)

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

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

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

如果你仔细观察,我认为你会看到statearticleId确实朝着同一方向发展。

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

xmaph的第三个参数指定了如何解析某些基础值。在articleId的情况下,它解析int,而state解析anyString

xmaph的第一个参数指定如何将该值转换为所需的返回类型。在articleId中,我们简单地应用了ArticleId构造函数。在state中,我们应用read函数。但在这两种情况下,我们都会从基础值转变为所需的回报类型:

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

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

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

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

我上传了boomerang 1.3.1,它将新的组合子添加到名为Strings的{​​{1}}模块中。此函数正确使用Read和Show实例。不幸的是,错误报告有点草率,因为当readshow失败时,它不会告诉我们它失败的原因或位置。但它总比没有好。)

使用它你现在可以写:

reads

如果我们提供无效状态,我们现在得到:

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