Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 如何使用alex/haskell实现python风格的缩进/删除标记?_Parsing_Haskell - Fatal编程技术网

Parsing 如何使用alex/haskell实现python风格的缩进/删除标记?

Parsing 如何使用alex/haskell实现python风格的缩进/删除标记?,parsing,haskell,Parsing,Haskell,我正在用Alex和Haskell为一种小型语言编写一个lexer 该语言被指定为具有pythonnesque有效缩进,每当缩进级别更改时,都会发出缩进标记或DEDENT标记 在传统的命令式语言(如C)中,您需要在lexer中保留一个global,并在每行使用缩进级别对其进行更新 这在Alex/Haskell中不起作用,因为我不能用Haskell在任何地方存储任何全局数据,也不能将所有的词法规则放在任何monad或任何东西中 那么,我该怎么做呢?有可能吗?还是我必须自己写lexer,避免使用ale

我正在用Alex和Haskell为一种小型语言编写一个lexer

该语言被指定为具有pythonnesque有效缩进,每当缩进级别更改时,都会发出缩进标记或DEDENT标记

在传统的命令式语言(如C)中,您需要在lexer中保留一个global,并在每行使用缩进级别对其进行更新

这在Alex/Haskell中不起作用,因为我不能用Haskell在任何地方存储任何全局数据,也不能将所有的词法规则放在任何monad或任何东西中

那么,我该怎么做呢?有可能吗?还是我必须自己写lexer,避免使用alex

我不能用Haskell在任何地方存储任何全局数据

事实并非如此;在大多数情况下,像这样的东西就足够了,但也有

但是,此任务不需要全局状态。编写解析器由两部分组成;词汇分析和句法分析。词法分析只是将字符流转换为有意义的标记流。语法分析将令牌转换为AST;这是您应该处理缩进的地方

在解释缩进时,您将在缩进级别更改时调用处理程序函数——当缩进级别增加(嵌套)时,您将调用处理程序函数(如果要跟踪缩进级别,可能会增加一个参数);当级别降低时,只需从函数返回相关的AST部分

(顺便说一句,在命令式语言中,使用全局变量也是我不会想到的——如果有的话,它是一个实例变量。State monad在概念上与此非常相似。)

最后,我认为短语“我不能把我所有的词法规则都放在任何单子里”表明了对单子的某种误解。如果我需要解析并保持全局状态,我的代码如下所示:

data AST = ...
type Step = State Int AST

parseFunction :: Stream -> Step
parseFunction s = do
   level <- get
   ...
   if anotherFunction then put (level + 1) >> parseFunction ...
   else parseWhatever
   ...
   return node

parse :: Stream -> Step
parse s = do
   if looksLikeFunction then parseFunction ...

main = runState parse 0 -- initial nesting of 0
(或

eval e(函数fxy)=((`eval`f)(`eval`x)(`eval`y))e
如果你有类似“funcall”的东西……但我离题了。)


有大量关于应用函子、单子和箭头解析的文献;所有这些都有可能解决您的问题。阅读这些内容,看看你得到了什么。

注意,在其他对空格敏感的语言中——比如Haskell——布局处理确实是在lexer中完成的。GHC实际上在Alex中实现了布局处理。以下是消息来源:

正如jrockway所指出的,在你的问题中有一些严重的错误会让你误入歧途。“我不能用Haskell在任何地方存储任何全局数据”是错误的。首先,您可以拥有全局状态,其次,当Alex以安全的方式完全支持规则中的状态转换时,您不应该在这里使用全局状态


看看Alex提供的AlexState结构,它允许您通过lexer线程化state。然后,看看在GHC的布局实现中如何使用状态来实现布局规则的缩进/取消缩进。(在GHC的lexer中搜索“-Layout processing”,查看状态是如何被推送和弹出的)。

Nice。最后我和亚历克斯玩了一会儿,发现在某些方面它比帕罗斯更干净(这通常是我想要的)。谢谢你的信息:)啊,谢谢你。我也在#haskell上问过,发现了alex的UserState包装器。虽然没有太多的文档,但必须进行一些源代码搜索。我知道State monad,但我不确定如何通过alex的lexer实现State。谢谢你的帮助。我对编程语言设计很熟悉,只是对haskell和alex不太熟悉。谢谢你提供的信息,但我已经知道了这一切。我所说的“不放置全局状态”是指不将其放置在状态单子中,而是具有一些可变状态。我说的“不把我的词汇规则放进单子”是指我无法通过Alex的规则来处理状态单子,事实证明,这是可以实现的。你所说的大部分对我来说都没有什么帮助,但在哈斯凯尔的帮助下,我还是能够解决这个问题。无论如何,谢谢。布局几乎总是在lexer中完成的,Python和哈斯凯尔都是这样做的。那么状态monad不是“可变状态”呢?尽管在技术上是不可变的,但在阅读(>>=)的源代码之前,您肯定不会注意到这一点。
eval :: Environment -> Node -> Evaluated
eval e (Constant x) = Evaluated x
eval e (Variable x) = Evaluated (lookup e x)
eval e (Function f x y) = (f <$> (`eval` x) <*> (`eval` y)) e
eval e (Function f x y) = ((`eval` f) <*> (`eval` x) <*> (`eval` y)) e