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

时间:2016-07-29 12:49:34

标签: elm

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

注意:以下代码使用combinator library

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) )

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

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

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

这是我迄今所理解的

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

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

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

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

感谢所有回复,我已更新解析器以解析粗体斜体下划线...,根据以下屏幕截图enter image description here

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]

2 个答案:

答案 0 :(得分:3)

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

anyChar成功时,它会消耗该单个字符,并在candThen内捕获该字符。然后,当对anyChar进行递归调用时,剩余的字符串(除styleParserItalic bolded捕获的字符之外的所有字符串)都会被“爬行”。第二个andThen将递归组合子的输出捕获到cs,并将捕获的字符预先添加到递归调用的其余字符列表中。

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

答案 1 :(得分:2)

首先是一些简单的......

(1)签名中内部列表的每个元素:

svg-slide

只是一个字符。只需从最后一行删除active

styleParserItalic : Bool -> Parser ( List (List Char , Style))
                                           ^^^^^^^^^

你可以让它有这个签名。

(2)请注意,:: []参数仅影响样式 - 它对控制流没有影响。它应该被称为 <|> ... `andThen` \cs -> succeed ((c ,style) :: cs) ) ^^^ removed `:: []` ,因为如果参数为True,输出中显示的样式为bolded,否则为italic

另请注意,一旦此参数设置为True,它将保持为True 所有后续的递归调用。

所以现在算法是:

  1. 如果在该行的末尾,则返回空列表。
  2. 如果在Italic,请在解析的其余部分使用Unstyled作为样式。
  3. 否则,解析一个字符,解析该行的其余部分并连接结果。
  4. 近似Python算法类似于:

    (!ITALIC!)