2012-06-27 57 views
2

如何翻譯這個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 F? –

+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

值得注意的是:monadic語法不再被推薦,特別是當性能是一個問題時(http://www.quanttec.com/fparsec/users-guide/where-is-the-monad.html)。 – Daniel

+0

@Daniel,當然,但這裏的解析器算法是動態的,你如何解決這個問題?無論如何,至少會有一個'>> =',因爲你不能用'Applicative'操作符來寫這個。除非'FParsec'中有某種'ifThenElse'? – t0yv0

3

使用toyvo的答案BracketElement類型,你可以不喜歡

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

非常感謝您,但您的計算與原始問題稍有不同。要測試它,你可以比較運行pBEChar「 - 」「;;和PR.parseTest p_set_elem_char「 - ]」(我做了原始代碼編譯)。 –

+0

哎呀...我誤讀了。你想要'followedByL'來代替。代碼已更正。 – 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")