2012-06-27 3 views
2

как перевести этот Haskell код:Перевести Haskell парсек в FParsec

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

вы по крайней мере, пытались это сделать yoursel е? –

+1

Пожалуйста, попробуйте, пожалуйста, сообщите нам свой предложенный код и объясните, почему он не соответствует вашим ожиданиям. –

+0

Да, но я новичок, поэтому у меня есть каракули. И я читал источники FParsec как собака: все понимаю, но ничего не могу сказать. Разрыв между активным и пассивным лексиконом :) –

ответ

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 
    } 
+0

Возможно, стоит отметить: монадический синтаксис больше не рекомендуется, особенно когда производительность вызывает беспокойство (http://www.quanttec.com/fparsec/users-guide/where-is-the-monad.html). – Daniel

+0

@ Даниэль, конечно, но алгоритм парсера здесь динамичен, как вы обходите это? В любом случае будет хотя бы один '>> =', поскольку вы не можете записать это в терминах операторов «Applicative». Разве что-то вроде 'ifThenElse' в' FParsec'? – t0yv0

3

BracketElement Использование типа в ответ Toyvo, вы могли бы сделать что-то вроде

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

Спасибо, но ваши вычисления немного отличаются от исходной проблемы. Чтобы проверить это, вы можете сравнить run pBEChar "-]" ;; и PR.parseTest p_set_elem_char "-]" (я сделал исходный компилируемый код). –

+0

К сожалению ... Я неправильно понял. Вместо этого вы хотите 'followByL'. Код исправлен. – Daniel

2

Подобно тому, что предложил Даниэль, вы могли бы написать, что синтаксический анализатор как

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

Если вы хотите добавить собственное сообщение об ошибке, вы можете использовать followedByL как в ответ Даниила или вы можете добавить сообщение, используя 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") 
Смежные вопросы