我已经搜索过试图找到一个简单的Haskell示例,用于定义一种简单的语言,但无济于事。
我确实在stackoverflow上找到了这个帖子给出了一个类似的例子,但是当我实现它时,它似乎不起作用:
Haskell - How to best to represent a programming language's grammar?
这种语言的示例表达式是:
如果为true则为x else(如果为false则为y,否则为true)您的Haskell数据类型 看起来像这样:
data Expr = Var String
| Lit Bool
| If Expr Expr Expr
然而,当我输入if if,然后x else(如果为false,则其他为真)作为输入进入控制台时,它抱怨“x”不可解释。它也不喜欢真假。
编辑:我最后也得到了“show”,
答案 0 :(得分:4)
创建编程语言有几个常见的步骤(当然还有其他一些):
您展示的data Expr
将成为语法树的一部分。 if true then ...
是程序文本。你需要一些从文本到树的方法:你需要一个解析器。
或者,您可以使用Haskell作为解析器,并将语法树编写为Haskell代码:
If True "it's true!" (If False "uh-oh" "it's false")
答案 1 :(得分:4)
Parsec has extensive programming-language-focused tools。这是一个开始的好地方。
可能需要一些时间来解决两件事之间的区别:
您的编程语言保存在文件中。
Haskell中该语言的表示。
这就是为什么你需要Lit True
而不只是true
。 true
是编程语言中的文本。 Lit True
是Haskell表示。链接这两者是解析器的用途。
要在评论中回答您的另一个问题,“主席桌”问题的基本解决方案是:
import Text.Parsec
data ProgrammableFurniture = ChairDesk
| CouchCoffeeTable
--a parser for the text "chair desk"
chairDesk = do string "chair"
char ' '
string "desk" <?> "Chair must be followed by desk!"
return ChairDesk
答案 2 :(得分:3)
如果您想用小语言表示if true then x else (if false then y else true)
,则需要使用以下表达式:
If (Lit True) (Var "x") (If (Lit False) (Var "y") (Lit True))
正如您所说,如果您派生Show
,那么这也会与输入完全一致。
我不确定你还想做什么!可能的其他事项是:
Show
实例以使打印的表示看起来更好。答案 3 :(得分:0)
与yatima2975的回答一样,你可以简单地推导出Read
。
data Expr = Var String
| Lit Bool
| If Expr Expr Expr
deriving (Read, Show)
然后,如果您在字符串上使用read
函数,其格式与yatima相同,则可以生成Expr
。请注意,我必须逃离“围绕内部琴弦。
ghci> read "If (Lit True) (Var \"x\") (If (Lit False) (Var \"y\") (Lit True))" :: Expr
If (Lit True) (Var "x") (If (Lit False) (Var "y") (Lit True))
这比定义您自己的Read
实例更简单,但您也可以这样做。
答案 4 :(得分:-1)
不幸的是,语言语法和解析没有达到定义编程语言的水平。定义语言的语义是最重要的部分,如果定义明确(必须通过定义来解决语言实现的一致性问题),就可以通过解释器或编译器来改进实现。
虽然Haskell是一种纯函数式语言,但对其懒惰评估存在批评,这引发了有关其性能推理的问题。
关于Haskell是否适合您的意图(一种简单的语言) - 或许首先描述您的意图更重要,然后尝试验证Haskell或其他语言是否符合您的标准作为最佳候选者用来定义你的编程语言。
当你在这里时,你可能想要查看Dana Scott的Denotational Semantics并将Lambda Calculus看作是定义编程语言的潜在语言(如果你能够接受挑战)。即使是简单的语言,为了有用,也应该在语义上明确定义。
答案 5 :(得分:-3)
语言的设计与实现
W.Pratt是一本很好读的书,之后最好阅读aho编译器书。
但毕竟这一切;你需要一些编译器算法和一些你应该遵循的原理。
例如,您应该编写一个扫描程序,用于检查变量名称中的错误。
例如,C ++扫描程序会在以下代码中找到错误:
int 32xy=0;
因为c ++变量不能以数字开头。
到目前为止,扫描仪有一个符号表来保存错误。扫描程序现在将符号表发送给解析器。
现在我们将编写一个解析器。
请注意我的答案很普遍。