从这篇关于2017年Nanopass编译器(https://github.com/sellout/recursion-scheme-talk/blob/master/nanopass-compiler-talk.org)的演讲中,我发现了下面的代码片段。在这段代码中,我看到了两个通用约束,我到处搜索以了解它们,但未能找到有关它们的任何信息。我希望了解的是:
**这些运营商在做什么?
- 他们从哪里来?
- 在最新版本的Scala和相关库中是否有更现代的等价物?
final case class Let[A](bindings: List[(String, A)], body: A)
final case class If[A](test: A, consequent: A, alt: A)
def expandLet[Lambda :<: F]: Fix[Let :+: F] => Fix[F] =
_.unFix match {
case Let(bindings, body) =>
bindings.unzip((names, exprs) =>
Fix(App(Fix(Lam(names, expandLet(body)).inject),
exprs.map(expandLet)).inject))
// and don’t forget the other cases
}
def expandIf[Lambda :<: F]: Fix[If :+: F] => Fix[F] =
_.unFix match {
case If(test, consequent, alt) =>
Fix(App(expandIf(test), List(
Fix(Lam(Nil, expandIf(consequent))),
Fix(Lam(Nil, expandIf(alt))))))
// seriously, still gotta handle the other cases
}
1条答案
按热度按时间jdg4fx2g1#
对不起,…我借用了一些Haskell-y类型的运算符,以使幻灯片上的内容更适合演讲,但我认为这只是造成了更多的困惑。
F :+: G
类似于Coproduct[F, G, ?]
,其中type Coproduct[F, G, A] = Either[F[A], G[A]]
。也就是说,它允许你组成模式函数器,用更小的片段构建更丰富的语言。F :<: G
稍微复杂一些。它将类似于Contains[F, G]
,其中所以这段代码的一个更好的版本(尽管仍然无效--我已经几年没有编写Scala了)是
我仍然在使用这项技术,只是不是在Scala中,而且我使用它的方式有了一些变化(例如,我会将
expandLet
变成一个代数,以消除递归调用)。但至少,那次演讲中的概念仍然是相关的。如果您想用Scala编写这样的代码,我认为Droste是目前的发展方向。