2

如何翻译这个 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
4

3 回答 3

3

使用BracketElementtoyvo 答案中的类型,您可以执行类似的操作

let pBEChar : Parser<_, unit> = 
  let c = 
    pchar '-' .>> followedByL (pchar ']') "A dash is in the wrong place in a bracket"
    <|> noneOf "-]"
  c |>> BEChar
于 2012-06-27T16:55:24.137 回答
2

Similar to what Daniel proposed, you could write that parser as

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

If you want to add your custom message to the error, you could use followedByL like in Daniel's answer or you could add the message using the fail primitive

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

A low-level implementation can be as simple as

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")
于 2012-07-19T21:52:58.077 回答
2

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

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
    }
于 2012-06-27T14:01:44.673 回答