Parsing 使用替代方法的纯应用程序解析器

Parsing 使用替代方法的纯应用程序解析器,parsing,haskell,applicative,higher-rank-types,alternative-functor,Parsing,Haskell,Applicative,Higher Rank Types,Alternative Functor,在上一篇文章中,用户为Haskell提供了一个纯应用程序解析器的实现(源代码)。下面是该解析器的部分实现: {-# LANGUAGE Rank2Types #-} import Control.Applicative (Alternative(..)) import Data.Foldable (asum, traverse_) 类型: newtype Parser a = Parser {run :: forall f. Alternative f => (Char -> f

在上一篇文章中,用户为Haskell提供了一个纯应用程序解析器的实现(源代码)。下面是该解析器的部分实现:

{-# LANGUAGE Rank2Types #-}

import Control.Applicative (Alternative(..))
import Data.Foldable (asum, traverse_)
类型:

newtype Parser a = Parser {run :: forall f. Alternative f => (Char -> f ()) -> f a}
实例如下:

instance Functor Parser where
    fmap f (Parser cont) = Parser $ \char -> f <$> cont char

instance Applicative Parser where
    pure a = Parser $ \char -> pure a
    (Parser contf) <*> (Parser cont) = Parser $ \char -> (contf char) <*> (cont char)

instance Alternative Parser where
    empty = Parser $ \char -> empty
    (Parser cont) <|> (Parser cont') = Parser $ \char -> (cont char) <|> (cont' char)
    some (Parser cont) = Parser $ \char -> some $ cont char
    many (Parser cont) = Parser $ \char -> many $ cont char
实例函子解析器,其中
fmap f(Parser cont)=Parser$\char->f cont char
实例应用程序解析器,其中
纯a=解析器$\char->纯a
(Parser contf)(Parser cont)=Parser$\char->(contf char)(cont char)
实例替代解析器,其中
empty=Parser$\char->empty
(Parser cont)(Parser cont')=Parser$\char->(cont char)(cont'char)
some(Parser cont)=Parser$\char->some$cont char
many(Parser cont)=Parser$\char->many$cont char
一些示例解析器:

item = Parser $ \char -> asum $ map (\c -> c <$ char c) ['A'..'z']
digit = Parser $ \char -> asum $ map (\c -> c <$ char (head $ show c)) [0..9]
string s = Parser $ \char -> traverse_ char s
item=Parser$\char->asum$map(\c->c asum$map(\c->c traverse\chars)

不幸的是,我很难理解如何使用这个解析器实现should/could以及我如何使用它进行简单的解析,例如从输入字符串中增加一个数字。如果可能的话,我想要一个具体的例子。有人能解释一下吗?

Char->f()部分表示单个字符上的匹配。也就是说,如果执行
字符“c”
,它将在
字符“c”
上匹配,并在其他所有字符上失败

要使用它,您可以将其转换为,比如说Parsec:

convert :: Parser a -> Parsec a
convert p = run p anyChar
p
基本上属于所有f的类型
。可选f=>(Char->f())->fa
,专门用于
(Char->Parsec())->Parsec a
。我们传入
anyChar
,它将使用
anyChar
和任何
可选操作生成
Parsec a


基本上,
解析器a
它是一个函数,用于匹配单个字符和一个
可选
实例,它将生成一个
可选
是提供给你的东西。如果你选择接受它,你的任务是只使用这两个位将其转换为
fa

  • Char->f()
    函数(即解析单个字符的方法:如果下一个字符与参数匹配,则解析成功;否则不会成功。)
  • f
那么如何将单个数字解析为
Int
?它的形式必须是

digit :: Parser Int
digit = Parser $ \parseChar -> _
必须使用工具包
parseChar::Char->f()创建
f Int
备选方案f
。我们知道如何解析单个
'0'
字符:
parseChar'0'
如果下一个字符是
'0'
,我们可以通过
f
函子
实例将其转换为
Int
的值,达到

digit0 :: Parser Int
digit0 = Parser $ \parseChar -> fmap (const 0) (parseChar '0')
但是
f
不仅仅是
函子
,它还是
替代品
,因此我们可以用

digit :: Parser Int
digit = Parser $ \parseChar -> fmap (const 0) (parseChar '0') <|>
                               fmap (const 1) (parseChar '1') <|>  
                               fmap (const 2) (parseChar '2') <|>  
                               fmap (const 3) (parseChar '3') <|>  
                               fmap (const 4) (parseChar '4') <|>  
                               fmap (const 5) (parseChar '5') <|>  
                               fmap (const 6) (parseChar '6') <|>  
                               fmap (const 7) (parseChar '7') <|>  
                               fmap (const 8) (parseChar '8') <|>  
                               fmap (const 9) (parseChar '9')

“链接”的结尾是否可以给出“<代码> f>代码>的两个例子?”“尤其是,我不理解Char -> f()应该是/可以是什么”——它不仅仅是<代码> Char > f()>代码>,它是<代码> FALL F。替代F= >(CHAR-> F())-F A < /代码>。您不能考虑类型“代码”> Char > -f-()。在隔离中,您必须同时考虑整个函数(因为通用量化)。您可以将此代码>语法分析器< /代码>视为所有(可选)解析器的最小上界-它不实现任何功能,相反,它依赖于最终将任何类型<代码> f>代码>实例化的语义。
digit :: Parser Int
digit = Parser $ \parseChar -> asum [fmap (const d) (parseChar c) | d <- [0..9], let [c] = show d]
digit :: Parser Int
digit = Parser $ \parseChar -> asum [d <$ parseChar c | d <- [0..9], let [c] = show d]