函数式编程:理解解析器组合

kha*_*mar 5 elm

我试图使用解析器组合器来解决问题.我尝试了以下方法:

注意:以下代码使用组合子库

styleParserItalic : Bool -> Parser ( List (List Char , Style))
styleParserItalic bolded =
let
style = if bolded then Italic else Unstyled
 in
 (end `andThen` always (  succeed ( [] )))
 <|> (string "(!ITALIC!)" `andThen`  \_ -> styleParserItalic ( not bolded )   ) 
 <|> ( anyChar `andThen` \c -> styleParserItalic bolded `andThen` \cs -> succeed ((c :: [],style) :: cs) )
Run Code Online (Sandbox Code Playgroud)

我很难理解这个解析器是如何运行的,因为styleParserItalic在解析器成功之前调用解析器.

有人可以解释解析器在给出一串字符时是如何工作的吗?

如果有人对解析器的目的和完整代码感兴趣,是我之前的问题.

这是迄今为止我所理解的

解析器将首先检查它是否是行的结尾,如果不是,它将尝试解析字符串,(!ITALIC!)如果情况那么它将使用参数True或false调用解析器(如果为false则将使其为真...)

如果解析器没有找到字符串(!ITALIC!),它将尝试解析任何字符,然后它将再次调用解析器.

令我困惑的是,解析器只要成功解析任何字符就会继续调用自己!

编辑:* 注意以下不是问题的一部分,如果有人有兴趣的话,只需分享代码

感谢所有回复,我更新了解析器以解析粗体斜体下划线...,如下面的屏幕截图所示在此输入图像描述

type Style = Bold| Unstyled | Italic | Coded | Lined | Titled | Marked     | Underline

styleParser : Bool ->Bool ->Bool ->Bool-> Bool-> Bool->Bool
                                -> Parser ( List (List Char ,     (Style,Style,Style,Style,Style,Style,Style)))
                                --(bold,italic ,code,line ,Titled,mark)
styleParser bolded italiced coded lined titled marked  underlined=
  let
    style = (
     if bolded     then Bold      else Unstyled
    ,if italiced   then Italic    else Unstyled
    ,if coded      then Coded     else Unstyled
    ,if lined      then Lined     else Unstyled
    ,if titled     then Titled    else Unstyled
    ,if marked     then Marked    else Unstyled
    ,if underlined then Underline else Unstyled
    )
  in
    (end `andThen` always ( succeed ( [] )))
    <|> (string "//"  `andThen` \_ -> styleParser  bolded      italiced         coded       lined       titled       marked        (not underlined))
    <|> (string "**"  `andThen` \_ -> styleParser (not bolded) italiced        coded       lined       titled       marked        underlined)
    <|> (string "*"   `andThen` \_ -> styleParser bolded       (not italiced)  coded       lined       titled       marked        underlined)
    <|> (string "`"   `andThen` \_ -> styleParser bolded       italiced        (not coded) lined       titled       marked        underlined)
    <|> (string "/br" `andThen` \_ -> styleParser bolded       italiced        coded       (not lined) titled       marked        underlined)
    <|> (string "/*"  `andThen` \_ -> styleParser bolded       italiced        coded       lined       (not titled) marked        underlined)
    <|> (string "{-"  `andThen` \_ -> styleParser bolded       italiced        coded       lined       titled       (not marked)  underlined)
    <|> ( anyChar     `andThen` \c -> styleParser bolded       italiced         coded       lined       titled       marked        underlined  `andThen`    \cs -> succeed ((c :: [],style) :: cs) )


foldStyleHtml : List ( List Char , (    Style,Style,Style,Style,Style,Style,Style) ) -> List (Html Msg)
foldStyleHtml lst =
  List.map styleToHtml lst


styleToHtml : ( List Char, (Style ,Style,Style,Style,Style,Style,Style)) -> Html Msg
styleToHtml (a,b) =
  case b of
    (Bold,Italic,_,_,_,_,Unstyled)       -> strong [] [em [][ text   (String.fromList a)]]
    (Bold,Italic,_,_,_,_,Underline)      -> u[][ strong [] [em [][ text (String.fromList a)]]]
    (Bold,Unstyled,_,_,_,_,Underline)    -> u[][ strong [] [text (String.fromList a)]]
    (Unstyled,Italic,_,_,_,_,Underline)  -> u[][ em     [] [text (String.fromList a)]]
(Unstyled,Italic,_,_,_,_,_)          -> em[] [text (String.fromList a)]
(Bold,Unstyled,_,_,_,_,_)            -> strong [][ text (String.fromList a)]
 (_,_,Coded,_,_,_,_)                  -> code   [codeStyle ][text     (String.fromList a)]
(_,_,_,Lined,_,_,_)                  -> br [][text " "]
  --  (_,_,_,_,Titled,_,_)                 -> div [][text (String.fromList a)]
    (_,_,_,_,_,Marked,_)                 -> mark [][text (String.fromList a)]
    (_,_,_,_,_,_,Underline)              -> u [][text (String.fromList a)]
   (_,_,_,_,_,_,_)                      -> text  (String.fromList a)

htmlParser : Parser  (List (Html Msg))
htmlParser =
 styleParser False False False False False False False `andThen` (succeed << foldStyleHtml )

runParser : Parser (List (Html Msg)) -> String -> Html Msg
runParser parser str                                    =
  case parse parser str of
    (Ok htmls,_)-> div [] htmls
    (Err err, _) -> div [ style [("color", "red")] ] [ text <| toString <| err]
Run Code Online (Sandbox Code Playgroud)

Cha*_*ert 3

解析器组合器(通常)在成功时消耗输入。在这个库中,如果string "(!ITALIC!)"失败,它不会消耗任何输入。由于<|>使用了组合器,因此它会尝试使用以 开头的代码的下一部分anyChar

当成功时,它会消耗该单个字符并在afteranyChar中捕获它。然后,当进行递归调用时,剩余的字符串(除了 捕获的字符之外的所有内容)都会被“爬行” 。这一秒将递归组合器的输出捕获到递归调用中,并将捕获的字符添加到其余字符列表中。candThenanyCharstyleParserItalic boldedandThencs

我认为要记住的重要部分是,组合器在成功时消耗输入,并且(通常)在失败时不消耗输入。