我正在寻找一些用FParsec编写的示例语法,它将超出项目存储库中的示例.
我发现了这个非常好的GLSL语法,但这是我发现的唯一样本.我需要的是一种类似于C或JavaScript的语言的语法.
我一直在考虑使用Haskell的Parsec解析库来解析Java的一个子集作为递归下降解析器,作为更传统的解析器生成器解决方案(如Happy)的替代.Parsec似乎很容易使用,解析速度绝对不是我的一个因素.不过,我想知道是否可以用Parsec实现"备份",这是一种通过依次尝试每个产品来找到正确生产的技术.举一个简单的例子,考虑JLS Java语法的开头:
Literal:
IntegerLiteral
FloatingPointLiteral
Run Code Online (Sandbox Code Playgroud)
我想要一种方法来不必弄清楚我应该如何命令这两个规则来使解析成功.就目前而言,这样一个天真的实现:
literal = do {
x <- try (do { v <- integer; return (IntLiteral v)}) <|>
(do { v <- float; return (FPLiteral v)});
return(Literal x)
}
Run Code Online (Sandbox Code Playgroud)
无法工作......像"15.2"之类的输入将导致整数解析器首先成功,然后整个事情将会扼杀"." 符号.当然,在这种情况下,您可以通过重新订购两个产品来解决问题.然而,在一般情况下,发现这样的事情将成为一场噩梦,我很可能会错过一些案例.理想情况下,我想要一种方法让Parsec为我找出这样的东西.这可能,或者我只是想对图书馆做太多事情?Parsec文档声称它可以"解析上下文敏感的,无限的前瞻语法",所以看起来像我应该能够在这里做点什么.
我是Haskell的新手,我正在尝试解析表达式.我发现了Parsec,我也发现了一些文章,但我似乎不明白我必须做什么.我的问题是我想给出一个像"x ^ 2 + 2*x + 3"这样的表达式,结果是一个带参数x并返回一个值的函数.如果这是一个简单的问题,我很抱歉,但我真的需要一些帮助.谢谢!我插入的代码来自您可以在此链接上找到的文章.
import Control.Monad(liftM)
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import Text.ParserCombinators.Parsec.Token
import Text.ParserCombinators.Parsec.Language
data Expr = Num Int | Var String | Add Expr Expr
| Sub Expr Expr | Mul Expr Expr | Div Expr Expr
| Pow Expr Expr
deriving Show
expr :: Parser Expr
expr = buildExpressionParser table factor
<?> "expression"
table = [[op "^" Pow AssocRight],
[op "*" Mul AssocLeft, op "/" Div AssocLeft],
[op "+" Add AssocLeft, op "-" …Run Code Online (Sandbox Code Playgroud) 我决定查看FParsec,并尝试为λ表达式编写解析器.事实证明,渴望使递归解析变得困难.我怎么解决这个问题?
码:
open FParsec
type ?Expr =
| Variable of char
| Application of ?Expr * ?Expr
| Lambda of char * ?Expr
let rec FV = function
| Variable v -> Set.singleton v
| Application (f, x) -> FV f + FV x
| Lambda (x, m) -> FV m - Set.singleton x
let ?0 = FV >> (=) Set.empty
let apply f p =
parse
{ let! v = p
return f v }
let ? e = …Run Code Online (Sandbox Code Playgroud) 我很惊讶我找不到任何关于此的信息.我必须是唯一一个遇到任何麻烦的人.
所以,假设我有一个破折计数器.我希望它计算字符串中的破折号数,并返回字符串.假装我给出了一个使用parsec状态处理无效的示例.所以这应该工作:
dashCounter = do
str <- many1 dash
count <- get
return (count,str)
dash = do
char '-'
modify (+1)
Run Code Online (Sandbox Code Playgroud)
事实上,这是编译.好的,我尝试使用它:
:t parse dashCounter "" "----"
parse dashCounter "" "----"
:: (Control.Monad.State.Class.MonadState
t Data.Functor.Identity.Identity,
Num t) =>
Either ParseError (t, [Char])
Run Code Online (Sandbox Code Playgroud)
好的,这是有道理的.它应该返回状态和字符串.凉.
>parse dashCounter "" "----"
<interactive>:1:7:
No instance for (Control.Monad.State.Class.MonadState
t0 Data.Functor.Identity.Identity)
arising from a use of `dashCounter'
Possible fix:
add an instance declaration for
(Control.Monad.State.Class.MonadState
t0 Data.Functor.Identity.Identity)
In the first argument of `parse', namely `dashCounter'
In the …Run Code Online (Sandbox Code Playgroud) 我在如何使用Haskell包Text.Parsec.Indent提供的模块中的任何函数时遇到了麻烦indents,Haskell是Parsec的一种附加组件.
所有这些功能都做了什么?它们如何使用?
我能理解的简单的黑线鳕描述withBlock,我发现了如何使用的例子withBlock,runIndent和IndentParser类型在这里,这里和这里.我也可以理解四个解析器indentBrackets和朋友的文档.但是很多事情仍然令我感到困惑.
特别是:
withBlock f a p和之间有什么区别
do aa <- a
pp <- block p
return f aa pp
Run Code Online (Sandbox Code Playgroud)
同样,withBlock' a p和之间有什么区别do {a; block p}
在职能indented和朋友的家庭中,"参考水平"是什么?那就是什么是'参考'?
再次,与功能indented和朋友,他们如何使用?除了withPos它之外,看起来它们没有参数并且都是类型IParser ()(IParser定义像这样或者这样)所以我猜他们所能做的就是产生错误或者它们应该出现在一个do块中,但我无法弄清楚细节.
我至少withPos在源代码中找到了一些关于使用的例子,所以如果我盯着它看足够久,我可能会想到这一点.
<+/>附带有用的描述" <+/>是缩进敏感的解析器是什么ap是monads"这是伟大的,如果你想花几个会议试图包裹你的头 …
约束(Stream s Identity t)在以下类型声明中意味着什么?
parse :: (Stream s Identity t)
=> Parsec s () a -> SourceName -> s -> Either ParseError a
Run Code Online (Sandbox Code Playgroud)
什么是Stream在下面的类的声明,这是什么意思.我完全迷失了.
class Monad m => Stream s m t | s -> t where
Run Code Online (Sandbox Code Playgroud)
当我使用Parsec时,我总是遇到带有type-signature(xxx :: yyy)的卡纸.我总是跳过签名,将src加载到ghci,然后将类型签名复制回我的.hs文件.它有效,但我仍然不明白所有这些签名是什么.
编辑:更多关于我的问题.
我仍然对类型签名的"上下文"感到困惑:
(Show a) =>
Run Code Online (Sandbox Code Playgroud)
意味着a必须是一个类的实例Show.
(Stream s Identity t) =>
Run Code Online (Sandbox Code Playgroud)
这种"背景"的含义是什么,因为t从未在此之后展示过=>
我有很多不同的解析器要运行,所以我编写了一个warp函数来运行任何带有真实文件的解析器.但问题出现了:
这是我的代码,它无法加载,我怎样才能使它工作?
module RunParse where
import System.IO
import Data.Functor.Identity (Identity)
import Text.Parsec.Prim (Parsec, parse, Stream) …Run Code Online (Sandbox Code Playgroud) Parsec在Haskell中是否(或可能有)反应(或任何其他纯函数解析器)?
简单地说,我想通过char自己提供解析器char,并获得足够多的结果以获得输出.
或者更简单,我怎么能这样做foldr或者至少map呢?
我们是否需要不同版本来支持这种反应行为?
编辑
我的问题特别是关于FRP.我用一个解析器作为例子,这是我能想到的最好的解释我的问题并大致了解我需要的东西.
我相信FRP不只是关于UI,对吗?
是否有可能以某种方式获得某些自定义类型的解析错误?例如,从错误中获取有关解析上下文的更多信息会很酷.以文本消息的形式出现错误信息似乎不太方便.
我想知道,如果在Haskell中有一个标准的,规范的方式,不仅要编写特定文件格式的解析器,还要编写一个编写器.
在我的例子中,我需要解析一个数据文件进行分析.但是,我还模拟要分析的数据并将其保存为相同的文件格式.我现在可以使用Parsec或类似的东西编写解析器,并编写以所需方式执行文本输出的函数,但每当我更改文件格式时,我都必须在代码中更改两个函数.有没有更好的方法来实现这一目标?
谢谢你,多米尼克
parsec ×10
haskell ×8
parsing ×6
f# ×2
fparsec ×2
file-writing ×1
frp ×1
indentation ×1
theory ×1
types ×1