【问题标题】:Translate Haskell parsec to FParsec将 Haskell parsec 转换为 FParsec
【发布时间】:2012-06-27 09:50:43
【问题描述】:

如何翻译这段 Haskell 代码:

import Text.ParserCombinators.Parsec((<|>), unexpected, lookAhead, noneOf, char)
import Control.Monad(when)

data BracketElement = BEChar Char | BEChars String | BEColl String | BEEquiv String | BEClass String

p_set_elem_char = do 
  c <- noneOf "]"
  when (c == '-') $ do
    atEnd <- (lookAhead (char ']') >> return True) <|> (return False)
    when (not atEnd) (unexpected "A dash is in the wrong place in a bracket")
  return (BEChar c)

到 FParsec ?最好的方法是不使用单子语法来提供良好的性能。

提前致谢,亚历山大。

抱歉有点误导。我稍微纠正了问题以使 Haskell 代码可编译:

import Text.ParserCombinators.Parsec((<|>), (<?>), unexpected, lookAhead, noneOf, char)
import Control.Monad(when)
import Data.Functor.Identity
import qualified Text.Parsec.Prim as PR

-- | BracketElement is internal to this module
data BracketElement = BEChar Char | BEChars String | BEColl String | BEEquiv String | BEClass String
                    deriving Show

p_set_elem_char :: PR.ParsecT [Char] u Identity BracketElement  
p_set_elem_char = do 
  c <- noneOf "]"
  when (c == '-') $ do
    atEnd <- (lookAhead (char ']') >> return True) <|> (return False)
    when (not atEnd) (unexpected "A dash is in the wrong place in a bracket")
  return (BEChar c)

现在可以重现 *p_set_elem_char* 计算。

我衷心感谢所有帮助过我的人。

我做了自己的近似,但不幸的是,它的功能并没有达到应有的水平:

type BracketElement = BEChar of char 
                    | BEChars of string 
                    | BEColl of string 
                    | BEEquiv of string 
                    | BEClass of string

let p_set_elem_char : Parser<BracketElement, _> = 
    fun stream ->
        let stateTag = stream.StateTag
        let reply = (noneOf "]") stream
        let chr = reply.Result
        let mutable reply2 = Reply(BEChar chr)
        if reply.Status = Error && stateTag = stream.StateTag then
            reply2.Status <- Error
            reply2.Error <-  reply.Error
        else if chr = '-' && stream.Peek() <> ']' then
            reply2.Status <- Error
            reply2.Error <- messageError ("A dash is in the wrong place in a bracket")
        reply2

【问题讨论】:

  • 您至少尝试过自己做这件事吗?
  • 请尝试一下,并向我们提供您建议的代码并解释为什么它不符合您的期望。
  • 是的,但我是新手,所以我得到了一些涂鸦。我像狗一样阅读 FParsec 的资料:完全了解所有内容,但不能说什么。主动和被动词典之间的差距:)
  • 哦,我的.. 看起来它会运行得很快。请注意 - 如果速度对您来说很重要,为什么还要使用 FParsec?手动编写的解析器将为您提供最高速度。
  • 您的代码看起来不错,但您不应该为如此琐碎的事情使用低级 API。

标签: haskell f# parsec fparsec


【解决方案1】:

使用BracketElement 输入 toyvo 的答案,您可以执行类似的操作

let pBEChar : Parser<_, unit> = 
  let c = 
    pchar '-' .>> followedByL (pchar ']') "A dash is in the wrong place in a bracket"
    <|> noneOf "-]"
  c |>> BEChar

【讨论】:

  • 非常感谢,但您的计算与原始问题略有不同。要对其进行测试,您可以比较运行 pBEChar "-]";;和 PR.parseTest p_set_elem_char "-]" (我使原始代码可编译)。
  • 糟糕...我看错了。你想要followedByL。代码已更正。
【解决方案2】:

我不太了解 FParsec,但这是一个幼稚的尝试,根据 cmets 对性能进行了一些修正:

type BracketElement =
    | BEChar of char
    | BEChars of string
    | BEColl of string
    | BEEquiv of string
    | BEClass of string

let parseBEChar : Parser<BracketElement,unit> =
    let okChars = noneOf "]"
    let endTest =
        (lookAhead (skipChar ']') >>. parse.Return(true))
        <|> parse.Return(false)
    let failure = fail "A dash is in the wrong place in a bracket"
    parse {
        let! c = okChars
        if c = '-' then
            let! atEnd = endTest
            if not atEnd then
                return! failure
            else
                return BEChar c
        else
            return BEChar c
    }

【讨论】:

  • 值得注意的是:不再推荐使用单子语法,尤其是在考虑性能时 (quanttec.com/fparsec/users-guide/where-is-the-monad.html)。
  • @Daniel,当然,但是这里的解析器算法是动态的,你如何解决这个问题?无论如何,至少会有一个&gt;&gt;=,因为你不能用Applicative 运算符来写这个。除非FParsec 中有某种ifThenElse
【解决方案3】:

与 Daniel 提出的类似,您可以将解析器编写为

let pSetElementChar : Parser<_,unit> = 
    satisfy (function '-' | ']' -> false | _ -> true)
    <|> (pchar '-' .>> followedByString "]")
    |>> BEChar

如果您想将自定义消息添加到错误中,您可以使用 followedByL 就像在 Daniel 的回答中一样,或者您可以使用 fail 原语添加消息

let pSetElementChar2 : Parser<_,unit> = 
  satisfy (function '-' | ']' -> false | _ -> true)
  <|> (pchar '-' .>> (followedByString "]" 
                      <|> fail "A dash is in the wrong place in a bracket"))
  |>> BEChar

低级实现可以很简单

let pSetElementChar3 : Parser<_,unit> =
  fun stream ->
    let c = stream.ReadCharOrNewline()
    if c <> EOS then
      if c <> '-' || stream.Peek() = ']' then Reply(BEChar c)
      else Reply(Error, messageError "A dash is in the wrong place in a bracket")
    else
      Reply(Error, unexpected "end of input")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    相关资源
    最近更新 更多