Haskell 具有简单代数数据类型的web路由回飞器

Haskell 具有简单代数数据类型的web路由回飞器,haskell,routes,boomerang,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 Si

我对如何正确使用回力棒生成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
这些类型完全不同,看起来方向相反,但我的
网站地图
可以正常工作,应用程序可以正确处理URL。我认为应该是这样的:

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

stateR :: Router State
stateR = xpure show maybeState
这不需要键入check,甚至可以在上面的
站点地图
中用
undefined
替换它的定义,
rState。stateR
可以工作,但是
r替换。(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
(此错误位于
站点地图的定义中):

Main.hs:45:18:
无法将预期的类型“String:-()”与实际的类型“()”匹配
预期类型:PrinterParser
StringsError[String]()(状态:-(String:-())
实际类型:路由器状态
在“()”的第一个参数中,即“state”
在“(.”的第二个参数中,即“(state anyString)”中

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

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

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
中,我们简单地应用
articleId
构造函数。在
状态
中,我们应用
读取
功能。但在这两种情况下,我们都从基础值转换为所需的返回类型:

ArticleId :: Int    -> ArticleId
read      :: String -> State
xmaph
的第二个参数指定如何将返回类型转换回基础值

show        :: State     -> String
unArticleId :: ArticleId -> Int
也就是说,我们实际上不应该在这里使用“read”,因为“read”可能会失败并通过错误。xmaph的第一个参数是total函数

我上传了boomerang 1.3.1,它在名为
readshow
Strings
模块中添加了一个新的组合器。此函数正确使用读取和显示实例。不幸的是,错误报告有点草率,因为当
读取失败时,它不会告诉我们失败的原因或位置。但总比什么都没有好:)

现在,您可以使用它来编写:

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.

我想,令我惊讶的是,从字符串到状态的转换可能会失败,而不是从状态到字符串的转换。使用
read
,我感觉有点脏——回力棒是否能处理read为我抛出异常的可能性?我应该拉两个字符而不是整个字符串吗?是的,实际上你根本不应该在那里使用read。我添加了一个新的readshow combinator,它可以满足您的需要。xmaph的第一个参数应该总是成功的(aka,是一个total函数)。尽管
xmaph
的第一个参数应该是
Maybe/other
函数。例如,如果int为负,
articleId
可能希望失败。。我得再想一想。反对它的理由是xmaph应该像fmap的双向版本,而fmap只是
a->b
。但这并不能解释为什么我们有
(b->也许a)
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.