Haskell HOA和FOA之间的差异

Haskell HOA和FOA之间的差异,haskell,abstract-syntax-tree,Haskell,Abstract Syntax Tree,在试图决定EDSL是否适合我的项目时,我阅读并描述了meta repa的实现。他们都提到了HOA和FOA。从第一篇论文开始 数据函数a其中 LitI::Int->FunC Int LitB::Bool->FunC Bool If::FunC Bool->FunC a->FunC a->FunC a While::(FunC s->s->FunC Bool)->(FunC s->FunC s) ->FunC s->FunC s 配对::FunC a->FunC b->FunC(a,b) 函数(a,

在试图决定EDSL是否适合我的项目时,我阅读并描述了meta repa的实现。他们都提到了HOA和FOA。从第一篇论文开始

数据函数a其中
LitI::Int->FunC Int
LitB::Bool->FunC Bool
If::FunC Bool->FunC a->FunC a->FunC a
While::(FunC s->s->FunC Bool)->(FunC s->FunC s)
->FunC s->FunC s
配对::FunC a->FunC b->FunC(a,b)
函数(a,b)->函数a
Snd::FunC(a,b)->FunC b
Prim1::String->(a->b)->FunC a->FunC b
Prim2::String->(a->b->c)->FunC a->FunC b->FunC c
值::a->FunC a
变量::字符串->函数a
我们还选择了更高阶的抽象语法来表示 具有变量绑定的构造。在上述数据类型中,只有 高阶结构是
,而

构造函数使其成为HOA时,如何处理
?为什么其他的施工人员都没有HOA

在第二篇文章中,是在HOAS树中编写的,然后(在编译时)转换为FOAS进行进一步处理。同样,我不明白HOAS.hs HOAS中定义的数据是什么,而FOASTyped中定义的数据是FOAS。该报的神秘引语是:

类型
Expr
[在HOAS.hs中]使用高阶抽象语法来表示程序。 这种表示法便于编程,但有一定的局限性 不太适合重写程序。因此,AST被转换为 一阶表示法[.]a 可能的实现方式是跳过[HOAS]
Expr
类型和 直接生成一阶表示。我们一直保持着 高阶表示部分是因为它有助于维护类型 实现的安全性,部分是因为它允许我们编写 一个打字准确、无标记的译员

HOA是否有比FOA更难转换的一般方式?与FOA相比,HOA如何帮助类型安全

我读过维基百科上关于FOAS和HOAS的文章,但这并没有为我澄清任何事情


Wikipedia建议HOA在使用可变绑定的语言中很有用(在第一段引用中也提到)。什么是变量绑定器,Haskell如何实现它,哪些语言没有变量绑定器?

在FOAS中,我们用标识符表示变量,所以

 data STLC = Var String
           | Lam String STLC
           | Unit
           | STLC :*: STLC

 term = Lam "a" $
        Lam "b" $
        Var "a" :*: (Lam "a" $ Var "a")
我们有显式变量,现在由我们来确保作用域和变量绑定正常工作。额外的工作有它的回报,但是,因为我们现在可以检查和模式匹配整个羔羊的身体,这是至关重要的大多数转换

HOAS本质上是我们使用宿主语言(Haskell)实现变量,而不是在AST中表示它们

例如,考虑STLC

  data STLC = Unit
            | Lam (STLC -> STLC)
            | STLC :*: STLC
注意我们如何使用Haskell函数
STLC->STLC
来表示由lambda绑定的变量。这意味着我们可以写作

  term = Lam $ \a ->
         Lam $ \b ->
         a :*: (Lam $ \a -> a)
它是有效的。在正常的AST中,我们必须确保正确地转换所有内容,以确保正确地尊重作用域。同样的优势也适用于所有绑定变量的东西(变量绑定器):Let表达式、continuations、异常处理程序等等

但这有一个主要缺点,因为
Lam
有一个完全抽象的函数,所以我们根本无法检查函数体。这使得很多转换都很好,很痛苦,因为所有的东西都被Haskell绑定包起来了

另一个好处是,因为我们没有为变量提供显式构造函数,所以所有项都保证是闭合的


通常这意味着我们用HOA和FOA的组合来表示事物。

jozefg的回答解释了什么是FOA和HOA,所以在这个回答中,我只是尝试回答问题中的各个小问题。我想先读一下jozefg的答案吧

While构造函数如何使其成为HOAS

让我们看一下
While
构造函数的第二个参数:
While::…->(FunC s->FunC s)->……
。在该字段的类型中,
FunC
显示在箭头的左侧。因此,如果在
FunC
程序中使用
While
,则程序不是内存中的抽象语法树,而是更复杂的东西。
FunC-s->FunC-s
的意思是“a
FunC-s
,具有类型为
s
的自由变量”。我猜这是用于while循环的主体,自由变量包含在每个循环迭代中更改的值

为什么其他的施工人员都没有HOA

他们没有
…->(FunC…->…)->…
我们在上面的
构造函数中看到的模式。因此,如果一个
FunC
值只使用其他构造函数,那么它的内存表示看起来就像一个抽象语法树

同样,我不明白HOAS.hs HOAS中定义的数据是什么,而FOASTyped中定义的数据是FOAS

您可以查看本文中代码的FOAS版本,了解他们如何在
期间更改
的类型以避免HOA模式,以及他们还需要更改哪些内容才能使其正常工作

HOA是否有比FOA更难转换的一般方式

HOAS程序不是树,因此无法在其上进行模式匹配。例如,您不能在
上进行模式匹配,而(\\\\\(LitB False))…
上,因为您不能像这样在lambda上进行匹配

与FOA相比,HOA如何帮助类型安全

在HOAS程序中,使用Haskell变量表示
FunC
变量。Haskell类型检查器将检查您是否仅在相应变量绑定的范围内使用Haskell变量。(GHC告诉您“不在范围内:
foo'
”,否则)。因为
FunC
变量表示为Haskell变量