解析器(Haskell)的更好应用实例

安茹

我正在完成Brent Yorgey Haskell课程的学习,而在定义Applicative的良好实例时遇到了麻烦。解析器的定义如下:

newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

该函数获取一个字符串,解析一定数量的输入,然后返回Maybe元组,其中第一个值是解析器的类型,其余为未解析的字符串余数。例如,这是一个用于正整数的解析器:

posInt :: Parser Integer
posInt = Parser f
  where
    f xs
      | null ns   = Nothing
      | otherwise = Just (read ns, rest)
      where (ns, rest) = span isDigit xs

任务是为解析器创建一个Applicative实例。我们从一个Functor实例开始(我认为这是相对简单的):

first :: (a -> b) -> (a,c) -> (b,c)
first f (a, c) = (f a, c)

instance Functor Parser where
  fmap f p = Parser f' 
    where f' s = fmap (first f) $ (runParser p) s

然后我尝试了Applicative:

collapse (Just (Just a)) = Just a
collapse _ = Nothing

extract (Just a, Just b) = Just (a,b)
extract _ = Nothing

appliedFunc :: Parser (a->b) -> Parser a -> String -> Maybe (b, String)
appliedFunc p1 p2 str = extract (f <*> fmap fst result2, fmap snd result2)
  where result1   = (runParser p1) str
        f         = fmap fst result1
        result2   = collapse $ fmap (runParser p2) $ fmap snd result1

instance Applicative Parser where
  pure a = Parser (\s -> Just (a, s))
  p1 <*> p2 = Parser (appliedFunc p1 p2)

y 所以我的问题是,如何使我的Applicative实例更整洁,更不易阅读?我觉得这个问题有一个简单的答案,但是我还无法确定这些类型。

ØrjanJohansen

我认为您还没有Monad课程。您正在使用的方式collapse,并fmap指示我,你基本上是重塑Monads到解决这个问题,特别是Monad Maybe实例。实际上,您collapsejoin此monad相同的确使用解决这个问题的一个非常优雅的方式,但也许有点“欺骗”在这一点上。以下是在使用您的函数时可以得到的最佳形状:

appliedFunc p1 p2 str = collapse $ fmap step1 (runParser p1 str)
  where
    step1 (f, str2) = collapse $ fmap step2 (runParser p2 str2)
      where
        step2 (x, str3) = Just (f x, str3)

一旦设置Monad正确,就应该可以使用更简洁的(>>=)运算符和/或do符号来重写它

几乎一样简单但又不需要重新构造monad的另一种替代方法是使用Maybes的显式模式匹配然后您会得到类似以下内容的信息:

appliedFunc p1 p2 str = case runParser p1 str of
    Nothing        -> Nothing
    Just (f, str2) -> case runParser p2 str2 of
        Nothing        -> Nothing
        Just (x, str3) -> Just (f x, str3)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Haskell Aeson - Gloss - JSON 实例解析器:颜色

来自分类Dev

Haskell的级联解析器

来自分类Dev

Haskell解析器组合器

来自分类Dev

Haskell Parsec组合器“很多”应用于接受空字符串的解析器

来自分类Dev

Haskell Parsec组合器“很多”应用于接受空字符串的解析器

来自分类Dev

在Haskell中合并解析器

来自分类Dev

使用Parsec的Haskell HTML解析器

来自分类Dev

用解析器组合器解析Haskell本身

来自分类Dev

应用解析器陷入无限循环

来自分类Dev

如何使用Haskell解析器解析任意列表?

来自分类Dev

真实世界的Haskell的CSV解析器实现

来自分类Dev

从头开始在Haskell中编写解析器

来自分类Dev

如何在EOF停止Haskell Parsec解析器

来自分类Dev

Haskell中使用GHCi的功能解析器示例

来自分类Dev

Haskell:Turtle:命令行解析器

来自分类Dev

具有拼写检查功能的haskell解析器

来自分类Dev

如何通过单词列表制作Haskell解析器?

来自分类Dev

在Haskell(Parsec)中链接两个解析器

来自分类Dev

使用monad进行简单的Haskell解析器

来自分类Dev

Haskell-编写一个小解析器

来自分类Dev

用 Haskell 为 Person 编写解析器

来自分类Dev

算术解析器

来自分类Dev

对话解析器

来自分类Dev

OsmInEdit的解析器

来自分类Dev

对话解析器

来自分类Dev

WikiRank 解析器

来自分类Dev

Haskell 解析中 CPS 与非 CPS 解析器的堆使用情况

来自分类Dev

是否可以使用JavaCC解析器解析String并对其应用分配法则?

来自分类Dev

C ++解析器如何区分比较和模板实例化?