fizruk / free-foil

Efficient Type-Safe Capture-Avoiding Substitution for Free (Scoped Monads).
https://fizruk.github.io/free-foil/haddock/
BSD 3-Clause "New" or "Revised" License
4 stars 0 forks source link
abstract-syntax haskell scala type-safe

Free Foil

Release `free-foil` on Hackage `free-foil` on Stackage Nightly `free-foil` on Stackage LTS

Haskell (build, test, haddock) Haddock

Generating Efficient and Scope-Safe Abstract Syntax with Free (Scoped) Monads and Template Haskell (with a partial port to Scala).

About

This project provides an implementation of the efficient scope-safe representation for syntax with binders (think λ-abstraction, let-binding, for-loop, etc.). The underlying representation is based on the IFL 2022 paper by Maclaurin, Radul, and Paszke «The Foil: Capture-Avoiding Substitution With No Sharp Edges»[^1]. This project extends the foil with patterns, as well as two techniques for free generation of the foil. The details are presented in the paper «Free Foil: Generating Efficient and Scope-Safe Abstract Syntax»[^2]. In brief:

  1. We introduce CoSinkable typeclass to generalize NameBinders to more complex patterns.
  2. We provide Template Haskell machinery to generate the proper scope-safe AST definitions as well as conversion functions, and helpers for patterns. This approach works particularly well with the code generated by tools like BNFC or BNFC-meta.
  3. We define a variant of free scoped monads[^3] with the foil instead of nested data types of Bird and Paterson. This approach allows implementing certain functions once for a large class of languages with binders. Here we implement only substitution, but more involved algorithms, such as generic higher-order preunification[^3] should be possible.

In addition to this repository, we have benchmarks comparing foil and free foil against each other and other implementation of λ-calculus. See KarinaTyulebaeva/lambda-n-ways, a fork of Stephanie Weirich's benchmark suite (sweirich/lambda-n-ways).

Project structure

Haskell

The Haskell code is organized into two packages as follows:

free-foil package

lambda-pi package

Scala

Scala implementation is not documented yet.

What is not (yet) in this project

In Haskell:

  1. We do not (yet) generate α-equivalence via Template Haskell or GHC.Generics. We do provide a generic α-equivalence functions for AST sig n, and demonstrate how to implement the check manually for λΠ-terms using the foil, but in generating this from Template Haskell or using GHC.Generics is left for future work.
  2. We do not (yet) demonstrate an implementation of the typechecker for λΠ in these representations. While it is largely straightforward the main non-trivial part is the equality for the Π-types, which relies on the α-equivalence from the previous item.
  3. The free foil does not (yet) support patterns, only single-variable binders. While we think it should be sufficient to parametrize AST and ScopedAST with a pattern type constructor (e.g. literally the same Pattern type used in the foil examples), we did not check if everything generalizes well enough.
  4. We do not (yet) provide strict versions of the foil and free foil here. The benchmarks, however, do implement these variations.
  5. We do not (yet) generate pattern synonyms for the foil with Template Haskell, however, this can be done easily, similarly to this implementation for free scoped monad.
  6. We derive CoSinkable and Sinkable instances via Template Haskell at the moment. However, a safer and more flexible derivation should be possible via GHC.Generics.
  7. Many functions, including rbind take in an extra argument of type Scope n, which is meant to be the runtime counterpart of the (phantom) type parameter n :: S. It might be possible to use singletons or a similar technique to avoid explicit passing of this argument, making the interface somewhat cleaner. However, since this would change the interface a lot, we do not plan on implementing this approach here.
  8. Dealing with scopes generically might enable generic delayed substitution, which plays a big part in normalization by evaluation (NbE) algorithms (which outperform naïve substitution-based evaluation). It should be possible to provide a generic framework for closures of scoped terms and delayed substitutions, but we have not yet investigated that fully.
  9. Free foil should allow the same generic implementation of higher-order unification as free scope monads[^2]. In fact, the parametrized metavariables should be added in the same data types à la carte fashion. However, we do not (yet) provide any generic binder-sensitive algorithms apart from substitution and α-equivalence.

[^1]: Dougal Maclaurin, Alexey Radul, and Adam Paszke. 2023. The Foil: Capture-Avoiding Substitution With No Sharp Edges. In Proceedings of the 34th Symposium on Implementation and Application of Functional Languages (IFL '22). Association for Computing Machinery, New York, NY, USA, Article 8, 1–10. https://doi.org/10.1145/3587216.3587224 [^2]: Nikolai Kudasov, Renata Shakirova, Egor Shalagin, Karina Tyulebaeva. 2024. Free Foil: Generating Efficient and Scope-Safe Abstract Syntax. To appear in ICCQ 2024. https://arxiv.org/abs/2405.16384 [^3]: Nikolai Kudasov. Free Monads, Intrinsic Scoping, and Higher-Order Preunification. To appear in TFP 2024. https://arxiv.org/abs/2204.05653