Parsing 使用替代方法的纯应用程序解析器
在上一篇文章中,用户为Haskell提供了一个纯应用程序解析器的实现(源代码)。下面是该解析器的部分实现: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
{-# 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]