<<

Foundations of meta-programming

Martin Berger

Cambridge, 9 August 2016 Based on joint work with Laurie Tratt and Christian Urban. I want to convince you that the answer is not a calculus.

To set the scene, let’s remember why λ-calculus is good, and how meta-programming came about.

Research programme

λ-calculus ??? = Functional programming Meta-programming To set the scene, let’s remember why λ-calculus is good, and how meta-programming came about.

Research programme

λ-calculus ??? = Functional programming Meta-programming

I want to convince you that the answer is not a calculus. Research programme

λ-calculus ??? = Functional programming Meta-programming

I want to convince you that the answer is not a calculus.

To set the scene, let’s remember why λ-calculus is good, and how meta-programming came about. M ::= x || MM || λx.M (λx.M)N → M[N/x]

The point of theory is to simplify, to focus on essence.

Why is λ-calculus so useful? The point of theory is to simplify, to focus on essence.

Why is λ-calculus so useful?

M ::= x || MM || λx.M (λx.M)N → M[N/x] The point of theory is to simplify, to focus on essence.

Why is λ-calculus so useful?

M ::= x || MM || λx.M (λx.M)N → M[N/x] Why is λ-calculus so useful?

M ::= x || MM || λx.M (λx.M)N → M[N/x]

The point of theory is to simplify, to focus on essence. I Strings

I Unicode

I FFI

I Backwards compatibility

I Modules

I Performance

I Ergonomics

I ...

Real-world programming languages: Real-world programming languages:

I Strings

I Unicode

I FFI

I Backwards compatibility

I Modules

I Performance

I Ergonomics

I ... In other words a real is: Let’s do theory Meta-programming: L-programs as data in L0.

Homogeneous meta-programming: MP where L = L0.

Homogeneous generative meta-programming (HGMP) is the generation of programs by a program as the latter is being either compiled or executed. Homogeneous meta-programming: MP where L = L0.

Homogeneous generative meta-programming (HGMP) is the generation of programs by a program as the latter is being either compiled or executed.

Meta-programming: L-programs as data in L0. Homogeneous generative meta-programming (HGMP) is the generation of programs by a program as the latter is being either compiled or executed.

Meta-programming: L-programs as data in L0.

Homogeneous meta-programming: MP where L = L0. Meta-programming: L-programs as data in L0.

Homogeneous meta-programming: MP where L = L0.

Homogeneous generative meta-programming (HGMP) is the generation of programs by a program as the latter is being either compiled or executed. Meta-programming is simple if you don’ care about convenient handling of programs as data. Just use strings. But first ...

Research on meta-programming is about convenient, principled, general purpose and safe handling of programs as data. Research on meta-programming is about convenient, principled, general purpose and safe handling of programs as data.

But first ... Quine invents quasi-quote and splicing (1940).

Lisp was the first language to support HGMP (1970s?).

MetaML destroyed the persistent myth that HGMP works only on syntactically simple languages like Lisp (1990s).

Haskell might have been the first typed mainstream language with principled HGMP support (2002).

History Lisp was the first language to support HGMP (1970s?).

MetaML destroyed the persistent myth that HGMP works only on syntactically simple languages like Lisp (1990s).

Haskell might have been the first typed mainstream language with principled HGMP support (2002).

History

Quine invents quasi-quote and splicing (1940). MetaML destroyed the persistent myth that HGMP works only on syntactically simple languages like Lisp (1990s).

Haskell might have been the first typed mainstream language with principled HGMP support (2002).

History

Quine invents quasi-quote and splicing (1940).

Lisp was the first language to support HGMP (1970s?). Haskell might have been the first typed mainstream language with principled HGMP support (2002).

History

Quine invents quasi-quote and splicing (1940).

Lisp was the first language to support HGMP (1970s?).

MetaML destroyed the persistent myth that HGMP works only on syntactically simple languages like Lisp (1990s). History

Quine invents quasi-quote and splicing (1940).

Lisp was the first language to support HGMP (1970s?).

MetaML destroyed the persistent myth that HGMP works only on syntactically simple languages like Lisp (1990s).

Haskell might have been the first typed mainstream language with principled HGMP support (2002). Uber lormal unentscheidbare S~tze der Principia Mathematica und verwandter Systeme I~). Von Kur~ GSdel in Wien.

it Die Entwicklung der Mathematik in der Richtung zu grS~erer Exaktheit hat bekanntlich dazu geftihrt, dal~ weite Gebiete yon ihr foi'malisiert wurden~ in der Art~ daft das Beweisen nach einigen wenigen mechanischen Regeln vollzogen werden kann. Die umfas- sendsten derzeit aufgestellten formalen Systeme sind das System der Principia Mathematica (PM)~) einerseits~ das Zermelo-Fraenkel- sche (yon . v. Neumann welter ausgebildete) Axiomensystem der ~engenlehre~) andererseits. Diese beiden Systeme sind so weir, da~ alle heute in der Mathematik angewendeten Beweismethoden in ihnen formalisiert, .h. auf einige wenige ~Axiome uad Schlultregeln zuriiek- geftihrt sind. Es liegt daher die Vermutung nahe, da~ diese Axiome und Sehlultregeln dazu ausreichen, alle mathematisehen Fragen~ die sich in den betreffenden Systemen tiberhaupt formal ausdriicken lassen: aueh zu entscheiden. Im folgenden wird gezeigt~ da~ dies nieht der Fall ist, sondern dait es in den beiden angefiihrten Systemen sogar relativ einfache Probleme aus der Theorie der ge- wShnliehen ganzen Zahlen gibt4)/die sich aus den Axiomen nicht

1) Vgl. die im Anzeiger der Akad. d. Wiss. in Wien (math.-naturw. KI.) 1930, Nr. 19 erschienene Zusammenfassung der Resultate dieser Arbeit. 3) A. Whitehead und B. Russell, Principia Mathematica, 2. Aufl., Cambridge 1925. Zu den Axiomen des Systems PM rechnen wir insbesondere aueh: Das Unendlichkeitsaxiom (in der Form: es gibt genau abziihlbar viele Individuen), das ReduzibilitAts- und das Auswahlaxiom (ftir alle Typen). ~) Vgl. A. Fraenkel, Zehn Vorlesungen iiber die Grundlegung der Men- genlehre, Wissensch. u. Hyp. Bd. XXXI. J,v. Neumann, Die Axiomatisierung der Mengenlehre. Math. Zeitschr. 27, 1928. Journ. f. reine u. angew. Math. 154 (1925), 160 (1929). Wir bemerken, daii man zu den in der angeftihrten Literatur gegebenen mengentheoretisehen Axiomen noeh die Axiome und Schh~regeln des Logikkalktils hinzufiigen muir, um die Formalisierung zu vollenden. -- Die naehfolgenden Oberlegungen gelten aueh ftir die in den letzten Jahren yon D. H ilb e t und seinen Mitarbeitern aufgestellten formalen Systeme (soweit diese bisher vorliegen). Vgl. D. Hilbert, Math. Ann. 88, Abh. aus d. math. Sem. der Univ. Hamburg I (1922), VI (1928). P. B ernay s, Math. Ann. 90. J.v.Neumann, Math. Zeitsehr. 26 (1927). W. Aekermann, Math. Ann. 93... 4) D.h. genauer, es gibt unentseheidbare Shtze, in denen aul]er den logi- sehen Konstanten: -- (nieht), V (0der), (x) (far alle), = (identiseh mit) keine anderen Begriffe vorkomfnen als + (Addition), . (Multip!ikation), beide bezogen auf nattirliehe Zahlen, wobei aueh die Pri~fixe (x) sich nur auf nattlrliehe Zahlen beziehen dtirfen.

And then there is ... And then there is ...

Uber lormal unentscheidbare S~tze der Principia Mathematica und verwandter Systeme I~). Von Kur~ GSdel in Wien.

it Die Entwicklung der Mathematik in der Richtung zu grS~erer Exaktheit hat bekanntlich dazu geftihrt, dal~ weite Gebiete yon ihr foi'malisiert wurden~ in der Art~ daft das Beweisen nach einigen wenigen mechanischen Regeln vollzogen werden kann. Die umfas- sendsten derzeit aufgestellten formalen Systeme sind das System der Principia Mathematica (PM)~) einerseits~ das Zermelo-Fraenkel- sche (yon J. v. Neumann welter ausgebildete) Axiomensystem der ~engenlehre~) andererseits. Diese beiden Systeme sind so weir, da~ alle heute in der Mathematik angewendeten Beweismethoden in ihnen formalisiert, d.h. auf einige wenige ~Axiome uad Schlultregeln zuriiek- geftihrt sind. Es liegt daher die Vermutung nahe, da~ diese Axiome und Sehlultregeln dazu ausreichen, alle mathematisehen Fragen~ die sich in den betreffenden Systemen tiberhaupt formal ausdriicken lassen: aueh zu entscheiden. Im folgenden wird gezeigt~ da~ dies nieht der Fall ist, sondern dait es in den beiden angefiihrten Systemen sogar relativ einfache Probleme aus der Theorie der ge- wShnliehen ganzen Zahlen gibt4)/die sich aus den Axiomen nicht

1) Vgl. die im Anzeiger der Akad. d. Wiss. in Wien (math.-naturw. KI.) 1930, Nr. 19 erschienene Zusammenfassung der Resultate dieser Arbeit. 3) A. Whitehead und B. Russell, Principia Mathematica, 2. Aufl., Cambridge 1925. Zu den Axiomen des Systems PM rechnen wir insbesondere aueh: Das Unendlichkeitsaxiom (in der Form: es gibt genau abziihlbar viele Individuen), das ReduzibilitAts- und das Auswahlaxiom (ftir alle Typen). ~) Vgl. A. Fraenkel, Zehn Vorlesungen iiber die Grundlegung der Men- genlehre, Wissensch. u. Hyp. Bd. XXXI. J,v. Neumann, Die Axiomatisierung der Mengenlehre. Math. Zeitschr. 27, 1928. Journ. f. reine u. angew. Math. 154 (1925), 160 (1929). Wir bemerken, daii man zu den in der angeftihrten Literatur gegebenen mengentheoretisehen Axiomen noeh die Axiome und Schh~regeln des Logikkalktils hinzufiigen muir, um die Formalisierung zu vollenden. -- Die naehfolgenden Oberlegungen gelten aueh ftir die in den letzten Jahren yon D. H ilb e r t und seinen Mitarbeitern aufgestellten formalen Systeme (soweit diese bisher vorliegen). Vgl. D. Hilbert, Math. Ann. 88, Abh. aus d. math. Sem. der Univ. Hamburg I (1922), VI (1928). P. B ernay s, Math. Ann. 90. J.v.Neumann, Math. Zeitsehr. 26 (1927). W. Aekermann, Math. Ann. 93... 4) D.h. genauer, es gibt unentseheidbare Shtze, in denen aul]er den logi- sehen Konstanten: -- (nieht), V (0der), (x) (far alle), = (identiseh mit) keine anderen Begriffe vorkomfnen als + (Addition), . (Multip!ikation), beide bezogen auf nattirliehe Zahlen, wobei aueh die Pri~fixe (x) sich nur auf nattlrliehe Zahlen beziehen dtirfen. Arithmetisation of syntax

Ob~r formal tmen~scheidbare Siitze der Principia Mathematica etc. 179

,,0" ... 1 ,,V"..- 7 ,,(~... ll ,,f~ ...3 ,~II" .:.9 71)".-. 13 ~~" . . . 5 ferner den Variablen n-ten Typs die Zahlen der Form p'~ (wo p eine Primzahl > 13 ist). Dadureh entsprieht jeder endliehen Reihe yon Grundzeiehen (also aueh jeder Formel) in sineindeutiger Weise eine endlishe Rsihe nattirlieher Zahlsn. Die sndlishen Reihen natiir- licher Zahlen bilden wir nun (wieder eineindeutig) auf nattirliche Zahlen ab, indem wir der Reihs nl, n,~.., nk dis Zahl 2,1.3,3...pk ~ sntsprechen lassen, wo pk dis k-ts Yrimzahl (der GrSl]e hash) be- dentet. Dadurch ist nicht nur jedem Grundzsichen, sondern auch jeder endlichen Reihe yon solchsn in eineindeutiger Wsise eine nattirliche Zahl zugeordnet. Aih-e dem Grundzeichen b~_,.A.~ Grup~nd- zeichenre.ihs)__a zugeordnete Zahl bezeich-nen--w~r-n{it (P (a). Sci ntiS-"

zeishen oder Reihen yon solchen gegeben. Wir ordnen ihr diejsnige Klasse (Relation) /~' (x,, x~... x=) zwisehen natiirliehen Zahlen zu, welche dann und nur dann zwischen x~, x o... x~ besteht, wenn es solehs a~, a~... a,~ gibt, daf~ x~= (P(a~) (i: 1, 2,... n) und 1/(a~, a~ . . . a.) gilt. Diejenigen Klassen nnd Relationen natiirlicher Zahlen, welehe auf diese Weise den bisher dsfinierten mstamathema- tisshen Begriffen, z.B. ,Variable", ,Formel", ,,SatzformeV, ,,Axiom", ,beweisbare Formel '~ usw. zugeordnst sind, bezeichnen wir mit denselben Worten in Kursivschriff. Der Satz, dag es im System P unentseheidbare Probleme gibt, lautet z. B. fo]genderma$en: Es gibt Satzformeln a, so dal~ weder a noch dis _Negation yon a beweis- bare 2Vormeln sind. Wir sehalten nun sine Zwisehenbetrashtung sin, die mit ~-cm-! formalen System P vorderhand niehts zu tun hat, nnd geben zuniichsr folgende Definition: Eine zahlentheoretische Funktion 2~) ~0 (X~, x: ... x,~) heist rekursiv definiert aus den zahlentheoretischen Funktionen 5 (xi, x~ ... x~_~) und y. (x~, x2 ... x,~+~), wenn fiir alle x2 ... x,, /~ ~.6) folgendss gilt: 'v (o, ~. :. x~) = `5 (x~ ... ~) ~ (2) ? (]r + 1, x~ ... x.) = ~. (]~, ~ (~, x~ ... x.), x~ ... x.). Eine zahlentheoretische Funktion ? hsi~t rekursiv, wenn cs eine sndliche Reihe yon zahlentheor.Fnnktmnen* ~, ~72... % gibt, wslehe mit ~ endet and dis Eigensehaft hat, dal~ jeds Funktion ~ der Reihs entwedsr aus zwsi dsr vorhergchsnden rskursiv definiert ist oder "~) D. h. ihr Definitionsbereieh ist die Klasse der nieht negativen ganzen Zahlen (bzw. der n-tupel yon solchen) und ihre Werte sind nicht negative ganze Zahlen. ~) Kleine lateinische Buchstaben (ev. mit Indizes) sind im folgenden immer Variable far nicht negative ganze Zahlen (falls nicht ausdrticklieh dus Gegenteil bemerkt ist). Much work done by proof theorists and the dependent types community, connection with ’our’ meta-programming not clear to me. See J. Harrison, Metatheory and Reflection in Theorem Proving: A Survey and Critique (1995) for more.

Arithmetisation of syntax

Ob~r formal tmen~scheidbare Siitze der Principia Mathematica etc. 179

,,0" ... 1 ,,V"..- 7 ,,(~... ll ,,f~ ...3 ,~II" .:.9 71)".-. 13 ~c~" . . . 5 ferner den Variablen n-ten Typs die Zahlen der Form p'~ (wo p eine Primzahl > 13 ist). Dadureh entsprieht jeder endliehen Reihe yon Grundzeiehen (also aueh jeder Formel) in sineindeutiger Weise eine endlishe Rsihe nattirlieher Zahlsn. Die sndlishen Reihen natiir- licher Zahlen bilden wir nun (wieder eineindeutig) auf nattirliche Zahlen ab, indem wir der Reihs nl, n,~.., nk dis Zahl 2,1.3,3...pk ~k sntsprechen lassen, wo pk dis k-ts Yrimzahl (der GrSl]e hash) be- Arithmetisation of syntax has been dentet. Dadurch ist nicht nur jedem Grundzsichen, sondern auch jeder endlichen Reihe yon solchsn in eineindeutiger Wsise eine nattirliche Zahl zugeordnet. Aih-e dem Grundzeichen b~_,.A.~ Grup~nd- zeichenre.ihs)__a zugeordnete Zahl bezeich-nen--w~r-n{it (P (a). Sci ntiS-" investigated in detail and led to powerful zeishen oder Reihen yon solchen gegeben. Wir ordnen ihr diejsnige Klasse (Relation) /~' (x,, x~... x=) zwisehen natiirliehen Zahlen zu, welche dann und nur dann zwischen x~, x o... x~ besteht, wenn es solehs a~, a~... a,~ gibt, daf~ x~= (P(a~) (i: 1, 2,... n) und 1/(a~, a~ . . . a.) gilt. Diejenigen Klassen nnd Relationen natiirlicher proof principles like logical reflection Zahlen, welehe auf diese Weise den bisher dsfinierten mstamathema- tisshen Begriffen, z.B. ,Variable", ,Formel", ,,SatzformeV, ,,Axiom", ,beweisbare Formel '~ usw. zugeordnst sind, bezeichnen wir mit denselben Worten in Kursivschriff. Der Satz, dag es im System P unentseheidbare Probleme gibt, lautet z. B. fo]genderma$en: Es gibt which strengthens the logic and Satzformeln a, so dal~ weder a noch dis _Negation yon a beweis- bare 2Vormeln sind. Wir sehalten nun sine Zwisehenbetrashtung sin, die mit ~-cm-! formalen System P vorderhand niehts zu tun hat, nnd geben zuniichsr folgende Definition: Eine zahlentheoretische Funktion 2~) ~0 (X~, x: ... x,~) computational reflection which makes heist rekursiv definiert aus den zahlentheoretischen Funktionen 5 (xi, x~ ... x~_~) und y. (x~, x2 ... x,~+~), wenn fiir alle x2 ... x,, /~ ~.6) folgendss gilt: 'v (o, ~. :. x~) = `5 (x~ ... ~) proofs shorter. ~ (2) ? (]r + 1, x~ ... x.) = ~. (]~, ~ (~, x~ ... x.), x~ ... x.). Eine zahlentheoretische Funktion ? hsi~t rekursiv, wenn cs eine sndliche Reihe yon zahlentheor.Fnnktmnen* ~, ~72... % gibt, wslehe mit ~ endet and dis Eigensehaft hat, dal~ jeds Funktion ~ der Reihs entwedsr aus zwsi dsr vorhergchsnden rskursiv definiert ist oder "~) D. h. ihr Definitionsbereieh ist die Klasse der nieht negativen ganzen Zahlen (bzw. der n-tupel yon solchen) und ihre Werte sind nicht negative ganze Zahlen. ~) Kleine lateinische Buchstaben (ev. mit Indizes) sind im folgenden immer Variable far nicht negative ganze Zahlen (falls nicht ausdrticklieh dus Gegenteil bemerkt ist). Arithmetisation of syntax

Ob~r formal tmen~scheidbare Siitze der Principia Mathematica etc. 179

,,0" ... 1 ,,V"..- 7 ,,(~... ll ,,f~ ...3 ,~II" .:.9 71)".-. 13 ~c~" . . . 5 ferner den Variablen n-ten Typs die Zahlen der Form p'~ (wo p eine Primzahl > 13 ist). Dadureh entsprieht jeder endliehen Reihe yon Grundzeiehen (also aueh jeder Formel) in sineindeutiger Weise eine endlishe Rsihe nattirlieher Zahlsn. Die sndlishen Reihen natiir- licher Zahlen bilden wir nun (wieder eineindeutig) auf nattirliche Zahlen ab, indem wir der Reihs nl, n,~.., nk dis Zahl 2,1.3,3...pk ~k sntsprechen lassen, wo pk dis k-ts Yrimzahl (der GrSl]e hash) be- Arithmetisation of syntax has been dentet. Dadurch ist nicht nur jedem Grundzsichen, sondern auch jeder endlichen Reihe yon solchsn in eineindeutiger Wsise eine nattirliche Zahl zugeordnet. Aih-e dem Grundzeichen b~_,.A.~ Grup~nd- zeichenre.ihs)__a zugeordnete Zahl bezeich-nen--w~r-n{it (P (a). Sci ntiS-" investigated in detail and led to powerful zeishen oder Reihen yon solchen gegeben. Wir ordnen ihr diejsnige Klasse (Relation) /~' (x,, x~... x=) zwisehen natiirliehen Zahlen zu, welche dann und nur dann zwischen x~, x o... x~ besteht, wenn es solehs a~, a~... a,~ gibt, daf~ x~= (P(a~) (i: 1, 2,... n) und 1/(a~, a~ . . . a.) gilt. Diejenigen Klassen nnd Relationen natiirlicher proof principles like logical reflection Zahlen, welehe auf diese Weise den bisher dsfinierten mstamathema- tisshen Begriffen, z.B. ,Variable", ,Formel", ,,SatzformeV, ,,Axiom", ,beweisbare Formel '~ usw. zugeordnst sind, bezeichnen wir mit denselben Worten in Kursivschriff. Der Satz, dag es im System P unentseheidbare Probleme gibt, lautet z. B. fo]genderma$en: Es gibt which strengthens the logic and Satzformeln a, so dal~ weder a noch dis _Negation yon a beweis- bare 2Vormeln sind. Wir sehalten nun sine Zwisehenbetrashtung sin, die mit ~-cm-! formalen System P vorderhand niehts zu tun hat, nnd geben zuniichsr folgende Definition: Eine zahlentheoretische Funktion 2~) ~0 (X~, x: ... x,~) computational reflection which makes heist rekursiv definiert aus den zahlentheoretischen Funktionen 5 (xi, x~ ... x~_~) und y. (x~, x2 ... x,~+~), wenn fiir alle x2 ... x,, /~ ~.6) folgendss gilt: 'v (o, ~. :. x~) = `5 (x~ ... ~) proofs shorter. ~ (2) ? (]r + 1, x~ ... x.) = ~. (]~, ~ (~, x~ ... x.), x~ ... x.). Eine zahlentheoretische Funktion ? hsi~t rekursiv, wenn cs eine sndliche Reihe yon zahlentheor.Fnnktmnen* ~, ~72... % gibt, wslehe mit ~ endet and dis Eigensehaft hat, dal~ jeds Funktion ~ der Reihs entwedsr aus zwsi dsr vorhergchsnden rskursiv definiert ist oder "~) D. h. ihr Definitionsbereieh ist die Klasse der nieht negativen ganzen Zahlen (bzw. der n-tupel yon solchen) und ihre Werte sind nicht negative ganze Zahlen. ~) Kleine lateinische Buchstaben (ev. mit Indizes) sind im folgenden immer Variable far nicht negative ganze Zahlen (falls nicht ausdrticklieh dus Gegenteil bemerkt ist).

Much work done by proof theorists and the dependent types community, connection with ’our’ meta-programming not clear to me. See J. Harrison, Metatheory and Reflection in Theorem Proving: A Survey and Critique (1995) for more. Most/all mainstream languages have some HGMP facilities, either as an upfront design decision (e.g. Scala, Rust, Javascript) or bolted on as the language evolved (e.g. C++).

Working programmers heavily use HGMP, e.g. C++ , smart-pointers, DSL embedding. Syntax extension for increasing language expressivity, higher performance through compile- or run-time specialisation.

In summary, meta-programming enables abstractions without run-time penalty. Thus MP resolves the tension between abstraction and performance, albeit at the cost of increasing language complexity.

Meta-programming, circa August 2016 Working programmers heavily use HGMP, e.g. C++ generic programming, smart-pointers, DSL embedding. Syntax extension for increasing language expressivity, higher performance through compile- or run-time specialisation.

In summary, meta-programming enables abstractions without run-time penalty. Thus MP resolves the tension between abstraction and performance, albeit at the cost of increasing language complexity.

Meta-programming, circa August 2016

Most/all mainstream languages have some HGMP facilities, either as an upfront design decision (e.g. Scala, Rust, Javascript) or bolted on as the language evolved (e.g. C++). In summary, meta-programming enables abstractions without run-time penalty. Thus MP resolves the tension between abstraction and performance, albeit at the cost of increasing language complexity.

Meta-programming, circa August 2016

Most/all mainstream languages have some HGMP facilities, either as an upfront design decision (e.g. Scala, Rust, Javascript) or bolted on as the language evolved (e.g. C++).

Working programmers heavily use HGMP, e.g. C++ generic programming, smart-pointers, DSL embedding. Syntax extension for increasing language expressivity, higher performance through compile- or run-time specialisation. Meta-programming, circa August 2016

Most/all mainstream languages have some HGMP facilities, either as an upfront design decision (e.g. Scala, Rust, Javascript) or bolted on as the language evolved (e.g. C++).

Working programmers heavily use HGMP, e.g. C++ generic programming, smart-pointers, DSL embedding. Syntax extension for increasing language expressivity, higher performance through compile- or run-time specialisation.

In summary, meta-programming enables abstractions without run-time penalty. Thus MP resolves the tension between abstraction and performance, albeit at the cost of increasing language complexity. Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. .

Is it a solved problem in practise? C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. debugging.

Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta. MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. debugging.

Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty. Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. debugging.

Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound. Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. debugging.

Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc. Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. debugging.

Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP. Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. debugging.

Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache. Tooling hard, e.g. debugging.

Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear. Is it a solved problem in practise? Scala just gutted it’s original HGMP approach, to be replaced by scala.meta.

C++ template meta-programming is not pretty.

MetaOcaml was found to be ... type-unsound.

Template Haskell has meta-programming, but not meta-meta-programming etc.

Major terminological confusion, e.g. CTMP vs RTMP, macros vs CTMP.

Javascript’s string-based MP is a security headache.

Implementations of hygiene sometimes buggy or slow or unclear.

Tooling hard, e.g. debugging. Is it a solved problem in theory? No convincing theory of HGMP program equality.

No convincing theory of HGMP types.

No convincing way of automatically adding HGMP to a base language.

No convincing specification and reasoning (e.g. program logics) about HGMP.

No convincing way of deriving semantics of embedded DSL from embedding

Is it a solved problem in theory? No convincing theory of HGMP types.

No convincing way of automatically adding HGMP to a base language.

No convincing specification and reasoning (e.g. program logics) about HGMP.

No convincing way of deriving semantics of embedded DSL from embedding

Is it a solved problem in theory?

No convincing theory of HGMP program equality. No convincing way of automatically adding HGMP to a base language.

No convincing specification and reasoning (e.g. program logics) about HGMP.

No convincing way of deriving semantics of embedded DSL from embedding

Is it a solved problem in theory?

No convincing theory of HGMP program equality.

No convincing theory of HGMP types. No convincing specification and reasoning (e.g. program logics) about HGMP.

No convincing way of deriving semantics of embedded DSL from embedding

Is it a solved problem in theory?

No convincing theory of HGMP program equality.

No convincing theory of HGMP types.

No convincing way of automatically adding HGMP to a base language. No convincing way of deriving semantics of embedded DSL from embedding

Is it a solved problem in theory?

No convincing theory of HGMP program equality.

No convincing theory of HGMP types.

No convincing way of automatically adding HGMP to a base language.

No convincing specification and reasoning (e.g. program logics) about HGMP. Is it a solved problem in theory?

No convincing theory of HGMP program equality.

No convincing theory of HGMP types.

No convincing way of automatically adding HGMP to a base language.

No convincing specification and reasoning (e.g. program logics) about HGMP.

No convincing way of deriving semantics of embedded DSL from embedding Good news 1: lot’s of open problems.

Good news 2: good solutions are immediately relevant for industry.

? Good news 3: problems look fairly tractable, no P = NP-like difficulties. Lot’s of theory ready to go, e.g. nominal techniques, proof assistants.

Not a solved problem, but ... Good news 2: good solutions are immediately relevant for industry.

? Good news 3: problems look fairly tractable, no P = NP-like difficulties. Lot’s of theory ready to go, e.g. nominal techniques, proof assistants.

Not a solved problem, but ...

Good news 1: lot’s of open problems. ? Good news 3: problems look fairly tractable, no P = NP-like difficulties. Lot’s of theory ready to go, e.g. nominal techniques, proof assistants.

Not a solved problem, but ...

Good news 1: lot’s of open problems.

Good news 2: good solutions are immediately relevant for industry. Not a solved problem, but ...

Good news 1: lot’s of open problems.

Good news 2: good solutions are immediately relevant for industry.

? Good news 3: problems look fairly tractable, no P = NP-like difficulties. Lot’s of theory ready to go, e.g. nominal techniques, proof assistants. Thinking about multiple levels of a language and their interactions is hard for humans.

[email protected]

Even humor can be based on this difficulty:

All PL researchers are liars.

Why are these problems still open? [email protected]

Even humor can be based on this difficulty:

All PL researchers are liars.

Why are these problems still open?

Thinking about multiple levels of a language and their interactions is hard for humans. Even humor can be based on this difficulty:

All PL researchers are liars.

Why are these problems still open?

Thinking about multiple levels of a language and their interactions is hard for humans.

[email protected] All PL researchers are liars.

Why are these problems still open?

Thinking about multiple levels of a language and their interactions is hard for humans.

[email protected]

Even humor can be based on this difficulty: Why are these problems still open?

Thinking about multiple levels of a language and their interactions is hard for humans.

[email protected]

Even humor can be based on this difficulty:

All PL researchers are liars. Adding HGMP is deceptively easy to the untrained eye ... just add a representing programs ...

Why are these problems still open?

There is a huge need for MP since working programmers manipulate programs all the time, but ... Adding HGMP is deceptively easy to the untrained eye ... just add a data type representing programs ...

Why are these problems still open?

There is a huge need for MP since working programmers manipulate programs all the time, but ... just add a data type representing programs ...

Why are these problems still open?

There is a huge need for MP since working programmers manipulate programs all the time, but ...

Adding HGMP is deceptively easy to the untrained eye ... Why are these problems still open?

There is a huge need for MP since working programmers manipulate programs all the time, but ...

Adding HGMP is deceptively easy to the untrained eye ... just add a data type representing programs ... How hard can it be? How hard can it be? Adding HGMP to mess, means we need to create meta-mess, meta-meta-mess ... and think about how mess, meta-mess, meta-meta-mess ... relate.

How hard can it be? Remember: real programming languages are a mess How hard can it be? Remember: real programming languages are a mess

Adding HGMP to mess, means we need to create meta-mess, meta-meta-mess ... and think about how mess, meta-mess, meta-meta-mess ... relate. Time for theory λ-calculus ??? = Functional programming Meta-programming

... that means we focus on the essential features of HGMP, and nothing else.

I Language representation (code as data)

I Language levels (base, meta, meta-meta ...)

I Navigation between language levels

I is driven by the base-language

Let’s simplify ... that means we focus on the essential features of HGMP, and nothing else.

I Language representation (code as data)

I Language levels (base, meta, meta-meta ...)

I Navigation between language levels

I Computation is driven by the base-language

Let’s simplify

λ-calculus ??? = Functional programming Meta-programming Let’s simplify

λ-calculus ??? = Functional programming Meta-programming

... that means we focus on the essential features of HGMP, and nothing else.

I Language representation (code as data)

I Language levels (base, meta, meta-meta ...)

I Navigation between language levels

I Computation is driven by the base-language But: What base language?

Let’s simplify

We ignore:

I Hygiene

I Types

I Notions of equality

I Beauty of syntax

I Efficiency, performance

I ... What base language?

Let’s simplify

We ignore:

I Hygiene

I Types

I Notions of equality

I Beauty of syntax

I Efficiency, performance

I ...

But: Let’s simplify

We ignore:

I Hygiene

I Types

I Notions of equality

I Beauty of syntax

I Efficiency, performance

I ...

But: What base language? This is not a bad choice.

What we really want is to add HGMP to arbitrary base languages. I.e. an explicit HGMP(·):

L 7→ L0

taking a programming language L as input and returning as output a language L0 that is the HGMPified version of L.

What base language?

The PL research community will likely say λ-calculus. What we really want is to add HGMP to arbitrary base languages. I.e. an explicit function HGMP(·):

L 7→ L0

taking a programming language L as input and returning as output a language L0 that is the HGMPified version of L.

What base language?

The PL research community will likely say λ-calculus.

This is not a bad choice. I.e. an explicit function HGMP(·):

L 7→ L0

taking a programming language L as input and returning as output a language L0 that is the HGMPified version of L.

What base language?

The PL research community will likely say λ-calculus.

This is not a bad choice.

What we really want is to add HGMP to arbitrary base languages. What base language?

The PL research community will likely say λ-calculus.

This is not a bad choice.

What we really want is to add HGMP to arbitrary base languages. I.e. an explicit function HGMP(·):

L 7→ L0

taking a programming language L as input and returning as output a language L0 that is the HGMPified version of L. Remember real-world programming languages:

We want the transition

mess → meta-mess

automatised ...

... so we can experiment with languages without being drowned in uninteresting minutiae.

Why arbitrary base language? We want the transition

mess → meta-mess

automatised ...

... so we can experiment with languages without being drowned in uninteresting minutiae.

Why arbitrary base language?

Remember real-world programming languages: ... so we can experiment with languages without being drowned in uninteresting minutiae.

Why arbitrary base language?

Remember real-world programming languages:

We want the transition

mess → meta-mess

automatised ... Why arbitrary base language?

Remember real-world programming languages:

We want the transition

mess → meta-mess

automatised ...

... so we can experiment with languages without being drowned in uninteresting minutiae. Research hypothesis

The foundation of meta-programming is the function HGMP(·):

λ-calculus HGMP(·) = Functional programming Meta-programming Note that HGMP(·) is a theoretical tool, it’s not intended to give nice result, e.g. good looking syntax. If HGMP(·) exists, is it generic in the choice of base language, or highly dependent on the details of base language?

Precise answers to these questions are not yet known, but I want to sketch why I think HGMP(·) is essentially generic in the choice of base.

I will look at the special case of HGMP(λ), and then generalise.

But first: PL empiricism: the HGMP design space

But ...

Does HGMP(·) exist at all (as a computable )? Precise answers to these questions are not yet known, but I want to sketch why I think HGMP(·) is essentially generic in the choice of base.

I will look at the special case of HGMP(λ), and then generalise.

But first: PL empiricism: the HGMP design space

But ...

Does HGMP(·) exist at all (as a computable algorithm)?

If HGMP(·) exists, is it generic in the choice of base language, or highly dependent on the details of base language? I will look at the special case of HGMP(λ), and then generalise.

But first: PL empiricism: the HGMP design space

But ...

Does HGMP(·) exist at all (as a computable algorithm)?

If HGMP(·) exists, is it generic in the choice of base language, or highly dependent on the details of base language?

Precise answers to these questions are not yet known, but I want to sketch why I think HGMP(·) is essentially generic in the choice of base. But first: PL empiricism: the HGMP design space

But ...

Does HGMP(·) exist at all (as a computable algorithm)?

If HGMP(·) exists, is it generic in the choice of base language, or highly dependent on the details of base language?

Precise answers to these questions are not yet known, but I want to sketch why I think HGMP(·) is essentially generic in the choice of base.

I will look at the special case of HGMP(λ), and then generalise. But ...

Does HGMP(·) exist at all (as a computable algorithm)?

If HGMP(·) exists, is it generic in the choice of base language, or highly dependent on the details of base language?

Precise answers to these questions are not yet known, but I want to sketch why I think HGMP(·) is essentially generic in the choice of base.

I will look at the special case of HGMP(λ), and then generalise.

But first: PL empiricism: the HGMP design space I What of MP?

I When is MP executed?

I How are programs represented as data?

PL empiricism: the HGMP design space PL empiricism: the HGMP design space

I What kind of MP?

I When is MP executed?

I How are programs represented as data? We restrict our attention to homogeneous meta-programming.

HGMP design space: What kind of MP?

I Homogeneous MP: the object- and the meta-language are identical (examples: Racket, Template Haskell, MetaOcaml, Converge).

I In heterogeneous MP object- and the meta-language are different (example: written in C from to x86). HGMP design space: What kind of MP?

I Homogeneous MP: the object- and the meta-language are identical (examples: Racket, Template Haskell, MetaOcaml, Converge).

I In heterogeneous MP object- and the meta-language are different (example: compiler written in C from Java to x86).

We restrict our attention to homogeneous meta-programming. We restrict our attention to homogeneous generative meta-programming (HGMP).

HGMP design space: What kind of MP?

I Generative MP: where an object-program is generated (put together) by a meta-program.

I Intensional MP: where an object-program is analysed (taken apart) by a meta-program, e.g. reflection. HGMP design space: What kind of MP?

I Generative MP: where an object-program is generated (put together) by a meta-program.

I Intensional MP: where an object-program is analysed (taken apart) by a meta-program, e.g. reflection.

We restrict our attention to homogeneous generative meta-programming (HGMP). Let’s look at them briefly. Consider the following criteria:

I Syntactic

I Support for generating only ’valid’ programs

I Expressivity

HGMP design space: How are programs represented as data?

I Using strings.

I ADTs (algebraic data types).

I Higher-level language support, e.g. upMLs, downMLs, quasi-quotes, inserts and splices. HGMP design space: How are programs represented as data?

I Using strings.

I ADTs (algebraic data types).

I Higher-level language support, e.g. upMLs, downMLs, quasi-quotes, inserts and splices.

Let’s look at them briefly. Consider the following criteria:

I Syntactic overhead

I Support for generating only ’valid’ programs

I Expressivity Example, selector function that chooses the i-the component from an n-tuple. let pi_1_0 = fun ( x ) -> x;; let pi_2_0 = fun ( x, _ ) -> x;; let pi_2_1 = fun ( _, x ) -> x;; let pi_3_0 = fun ( x, _, _ ) -> x;; let pi_3_1 = fun ( _, x, _ ) -> x;; let pi_3_2 = fun ( _, _, x ) -> x;; let pi_4_0 = fun ( x, _, _, _ ) -> x;; let pi_4_1 = fun ( _, x, _, _ ) -> x;; let pi_4_2 = fun ( _, _, x, _ ) -> x;; let pi_4_3 = fun ( _, _, _, x ) -> x;; let pi_5_0 = fun ( x, _, _, _, _ ) -> x;; let pi_5_1 = fun ( _, x, _, _, _ ) -> x;; let pi_5_2 = fun ( _, _, x, _, _ ) -> x;; let pi_5_3 = fun ( _, _, _, x, _ ) -> x;; let pi_5_4 = fun ( _, _, _, _, x ) -> x;;

selector.ml

Strings Strings Example, selector function that chooses the i-the component from an n-tuple. let pi_1_0 = fun ( x ) -> x;; let pi_2_0 = fun ( x, _ ) -> x;; let pi_2_1 = fun ( _, x ) -> x;; let pi_3_0 = fun ( x, _, _ ) -> x;; let pi_3_1 = fun ( _, x, _ ) -> x;; let pi_3_2 = fun ( _, _, x ) -> x;; let pi_4_0 = fun ( x, _, _, _ ) -> x;; let pi_4_1 = fun ( _, x, _, _ ) -> x;; let pi_4_2 = fun ( _, _, x, _ ) -> x;; let pi_4_3 = fun ( _, _, _, x ) -> x;; let pi_5_0 = fun ( x, _, _, _, _ ) -> x;; let pi_5_1 = fun ( _, x, _, _, _ ) -> x;; let pi_5_2 = fun ( _, _, x, _, _ ) -> x;; let pi_5_3 = fun ( _, _, _, x, _ ) -> x;; let pi_5_4 = fun ( _, _, _, _, x ) -> x;;

selector.ml Advantages of string-based MP

I Flexible, expressive.

I Easy to do for basic MP.

I Ubiquitous support.

I Not restricted to a single target language. NB Lack of hygiene is sometimes useful, especially in large-scale MP.

We reject strings in our foundational approach.

Disadvantages of string-based MP

I No language support for constructing syntactically correct programs.

I No support for “hygiene”, i.e. sane management of free and bound variables. Hygiene is hard to add for strings. We reject strings in our foundational approach.

Disadvantages of string-based MP

I No language support for constructing syntactically correct programs.

I No support for “hygiene”, i.e. sane management of free and bound variables. Hygiene is hard to add for strings.

NB Lack of hygiene is sometimes useful, especially in large-scale MP. Disadvantages of string-based MP

I No language support for constructing syntactically correct programs.

I No support for “hygiene”, i.e. sane management of free and bound variables. Hygiene is hard to add for strings.

NB Lack of hygiene is sometimes useful, especially in large-scale MP.

We reject strings in our foundational approach. sealed abstract class Binop case class Add () extends Binop case class Sub () extends Binop case class Mul () extends Binop case class Div () extends Binop case class Eq () extends Binop

sealed abstract class Term case class CInt ( n : Int ) extends Term case class Op2 ( m : Term, op : Binop, n : Term ) extends Term case class Var ( x : Int ) extends Term case class App ( m : Term, n : Term ) extends Term case class Lam ( x : Int, m : Term ) extends Term case class Rec ( f : Int, x : Int, m : Term ) extends Term case class If ( c : Term, m : Term, n : Term ) extends Term

We call this representation AST (abstract syntax ), the workhorse of HGMP.

ADTs ADTs

sealed abstract class Binop case class Add () extends Binop case class Sub () extends Binop case class Mul () extends Binop case class Div () extends Binop case class Eq () extends Binop

sealed abstract class Term case class CInt ( n : Int ) extends Term case class Op2 ( m : Term, op : Binop, n : Term ) extends Term case class Var ( x : Int ) extends Term case class App ( m : Term, n : Term ) extends Term case class Lam ( x : Int, m : Term ) extends Term case class Rec ( f : Int, x : Int, m : Term ) extends Term case class If ( c : Term, m : Term, n : Term ) extends Term

We call this representation AST (abstract syntax tree), the workhorse of HGMP. Advantage:

I ADTs only construction of syntactically valid programs (may fail to type-check). Disadvantages:

I Verbose.

I No support for “hygiene”, i.e. sane management of free and bound variables. But hygiene is easy to add.

Advantages and disadvantages of ADTs I ADTs only construction of syntactically valid programs (may fail to type-check). Disadvantages:

I Verbose.

I No support for “hygiene”, i.e. sane management of free and bound variables. But hygiene is easy to add.

Advantages and disadvantages of ADTs

Advantage: I Verbose.

I No support for “hygiene”, i.e. sane management of free and bound variables. But hygiene is easy to add.

Advantages and disadvantages of ADTs

Advantage:

I ADTs only construction of syntactically valid programs (may fail to type-check). Disadvantages: I No support for “hygiene”, i.e. sane management of free and bound variables. But hygiene is easy to add.

Advantages and disadvantages of ADTs

Advantage:

I ADTs only construction of syntactically valid programs (may fail to type-check). Disadvantages:

I Verbose. Advantages and disadvantages of ADTs

Advantage:

I ADTs only construction of syntactically valid programs (may fail to type-check). Disadvantages:

I Verbose.

I No support for “hygiene”, i.e. sane management of free and bound variables. But hygiene is easy to add. ... to combine the terseness of strings with the guarantees of syntactic correctness that ASTs offer.

What we really want is ... What we really want is ...

... to combine the terseness of strings with the guarantees of syntactic correctness that ASTs offer.

Enter upMLs and downMLs, another good idea from logic, first introduced in Lisp.

UpMLs (AKA quasi-quotes, backquotes) are quotes with holes. In the holes we can execute arbitrary programs that produces code.

DownMLs (AKA splices or inserts) are the corresponding un-quotation mechanism.

UpMLs and downML UpMLs and downML

Enter upMLs and downMLs, another good idea from logic, first introduced in Lisp.

UpMLs (AKA quasi-quotes, backquotes) are quotes with holes. In the holes we can execute arbitrary programs that produces code.

DownMLs (AKA splices or inserts) are the corresponding un-quotation mechanism. UpML (Up MetaLevel) represent AST (or AST-like) structures by quoted chunks of normal program syntax. We have chosen the term ’upMLs’ to highlight an important relationship with downMLs.

↑{2 + 3}

is short for

astadd(astint(2), astint(3))

UpMLs are “syntactic sugar” for ASTs.

UpMLs and downML ↑{2 + 3}

is short for

astadd(astint(2), astint(3))

UpMLs are “syntactic sugar” for ASTs.

UpMLs and downML

UpML (Up MetaLevel) represent AST (or AST-like) structures by quoted chunks of normal program syntax. We have chosen the term ’upMLs’ to highlight an important relationship with downMLs. is short for

astadd(astint(2), astint(3))

UpMLs are “syntactic sugar” for ASTs.

UpMLs and downML

UpML (Up MetaLevel) represent AST (or AST-like) structures by quoted chunks of normal program syntax. We have chosen the term ’upMLs’ to highlight an important relationship with downMLs.

↑{2 + 3} astadd(astint(2), astint(3))

UpMLs are “syntactic sugar” for ASTs.

UpMLs and downML

UpML (Up MetaLevel) represent AST (or AST-like) structures by quoted chunks of normal program syntax. We have chosen the term ’upMLs’ to highlight an important relationship with downMLs.

↑{2 + 3}

is short for UpMLs are “syntactic sugar” for ASTs.

UpMLs and downML

UpML (Up MetaLevel) represent AST (or AST-like) structures by quoted chunks of normal program syntax. We have chosen the term ’upMLs’ to highlight an important relationship with downMLs.

↑{2 + 3}

is short for

astadd(astint(2), astint(3)) UpMLs and downML

UpML (Up MetaLevel) represent AST (or AST-like) structures by quoted chunks of normal program syntax. We have chosen the term ’upMLs’ to highlight an important relationship with downMLs.

↑{2 + 3}

is short for

astadd(astint(2), astint(3))

UpMLs are “syntactic sugar” for ASTs. DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}}

↑{2 + 3}

astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}}

↑{2 + 3}

astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. ↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}}

↑{2 + 3}

astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1): ↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}}

↑{2 + 3}

astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}} ↑{2+ ↓{astint(3)}}

↑{2 + 3}

astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}} ↑{2 + 3}

astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}} astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}}

↑{2 + 3} NB: DownMLs make sense only within the process of AST generation.

UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}}

↑{2 + 3}

astadd(astint(2), astint(3)) UpMLs and downML DownML (Down MetaLevel) indicate “holes” in upMLs. Inside the holes, arbitrary computation takes place during the evaluation of an upML. That computation must yield an AST. Exampe: with M = λx.astint(x − 1):

↑{2+ ↓{M 4}}

↑{2+ ↓{astint(4 − 1)}}

↑{2+ ↓{astint(3)}}

↑{2 + 3}

astadd(astint(2), astint(3))

NB: DownMLs make sense only within the process of AST generation. Welcome to Racket v6.5. > (quasiquote (+ 2 3)) ’(+ 2 3)

> ( (quasiquote (+ 2 3))) 5

> (define f (lambda (x) (quasiquote (* (unquote x) (unquote x)))))

> (f 5) ’(* 5 5)

> (eval (f 5)) 25

> (define g (lambda (x) (quasiquote (* 8 (unquote (f x))))))

> (g 3) ’(* 8 (* 3 3))

> (eval (g 3)) 72

racket.r

UpML and DownML in Racket UpML and DownML in Racket

Welcome to Racket v6.5. > (quasiquote (+ 2 3)) ’(+ 2 3)

> (eval (quasiquote (+ 2 3))) 5

> (define f (lambda (x) (quasiquote (* (unquote x) (unquote x)))))

> (f 5) ’(* 5 5)

> (eval (f 5)) 25

> (define g (lambda (x) (quasiquote (* 8 (unquote (f x))))))

> (g 3) ’(* 8 (* 3 3))

> (eval (g 3)) 72

racket.r By default upMLs in Racket, MetaOCaml, Converge and other languages are hygienic, i.e. prevent capture of free variables. This is an implementation choice, but not necessary. Advanced MP languages like Racket or Converge offer both, capturing and non-capturing behaviour.

We will strictly separate both concepts, i.e. our upMLs are not hygienic.

UpMLs and hygiene We will strictly separate both concepts, i.e. our upMLs are not hygienic.

UpMLs and hygiene

By default upMLs in Racket, MetaOCaml, Converge and other languages are hygienic, i.e. prevent capture of free variables. This is an implementation choice, but not necessary. Advanced MP languages like Racket or Converge offer both, capturing and non-capturing behaviour. UpMLs and hygiene

By default upMLs in Racket, MetaOCaml, Converge and other languages are hygienic, i.e. prevent capture of free variables. This is an implementation choice, but not necessary. Advanced MP languages like Racket or Converge offer both, capturing and non-capturing behaviour.

We will strictly separate both concepts, i.e. our upMLs are not hygienic. Some languages support both (e.g. Converge, scala.meta).

The difference is subtle. The result of CTMP is ’frozen’ (e.g. by saving the produced executable), multiple evaluations of a CTMP’ed program can be done with one compilation. RTMP’ed programs are regenerated on every run. Whether that leads to observable differences depends on the available language features.

HGMP design space: When is MP executed?

I At compile-time: e.g. the Lisp family, Template Haskell, Converge, C++. We call this CTMP.

I At run-time: e.g. the MetaML family, Javascript, printf-based MP. We call this RTMP. The difference is subtle. The result of CTMP is ’frozen’ (e.g. by saving the produced executable), multiple evaluations of a CTMP’ed program can be done with one compilation. RTMP’ed programs are regenerated on every run. Whether that leads to observable differences depends on the available language features.

HGMP design space: When is MP executed?

I At compile-time: e.g. the Lisp family, Template Haskell, Converge, C++. We call this CTMP.

I At run-time: e.g. the MetaML family, Javascript, printf-based MP. We call this RTMP.

Some languages support both (e.g. Converge, scala.meta). HGMP design space: When is MP executed?

I At compile-time: e.g. the Lisp family, Template Haskell, Converge, C++. We call this CTMP.

I At run-time: e.g. the MetaML family, Javascript, printf-based MP. We call this RTMP.

Some languages support both (e.g. Converge, scala.meta).

The difference is subtle. The result of CTMP is ’frozen’ (e.g. by saving the produced executable), multiple evaluations of a CTMP’ed program can be done with one compilation. RTMP’ed programs are regenerated on every run. Whether that leads to observable differences depends on the available language features. Evaluates code at run-time using eval and prints ... 1 3 6

Replacing the eval with a downML to get compile-time evaluation: print(1); print(2 + ↓{print(3); ASTInt(4)}) yields ... 3 1 6

The 3 is printed during compilation, the 1 6 is printed every time the compiled code is run.

HGMP design space: When is MP executed?

Example. print(1); print(2 + eval(print(3); ASTInt(4))) 1 3 6

Replacing the eval with a downML to get compile-time evaluation: print(1); print(2 + ↓{print(3); ASTInt(4)}) yields ... 3 1 6

The 3 is printed during compilation, the 1 6 is printed every time the compiled code is run.

HGMP design space: When is MP executed?

Example. print(1); print(2 + eval(print(3); ASTInt(4))) Evaluates code at run-time using eval and prints ... Replacing the eval with a downML to get compile-time evaluation: print(1); print(2 + ↓{print(3); ASTInt(4)}) yields ... 3 1 6

The 3 is printed during compilation, the 1 6 is printed every time the compiled code is run.

HGMP design space: When is MP executed?

Example. print(1); print(2 + eval(print(3); ASTInt(4))) Evaluates code at run-time using eval and prints ... 1 3 6 3 1 6

The 3 is printed during compilation, the 1 6 is printed every time the compiled code is run.

HGMP design space: When is MP executed?

Example. print(1); print(2 + eval(print(3); ASTInt(4))) Evaluates code at run-time using eval and prints ... 1 3 6

Replacing the eval with a downML to get compile-time evaluation: print(1); print(2 + ↓{print(3); ASTInt(4)}) yields ... HGMP design space: When is MP executed?

Example. print(1); print(2 + eval(print(3); ASTInt(4))) Evaluates code at run-time using eval and prints ... 1 3 6

Replacing the eval with a downML to get compile-time evaluation: print(1); print(2 + ↓{print(3); ASTInt(4)}) yields ... 3 1 6

The 3 is printed during compilation, the 1 6 is printed every time the compiled code is run. Language Strings ASTs UpMLs CT-HGMP RT-HGMP Converge ••••• JavaScript • ◦ ◦ ◦ • Lisp ••••• MetaML ◦ ◦ • ◦ • Haskell ◦ • • • ◦ Scala ◦ • • • •

Modern languages and HGMP Modern languages and HGMP

Language Strings ASTs UpMLs CT-HGMP RT-HGMP Converge ••••• JavaScript • ◦ ◦ ◦ • Lisp ••••• MetaML ◦ ◦ • ◦ • Haskell ◦ • • • ◦ Scala ◦ • • • • We start with the untyped λ-calculus, and CBV.

M ::= x || MN || λx.M || c || M + N || ...

ASTs are the key representation of programs as data. So we add AST constructs for each element of the base language:

˜ M ::= ... || astt(M) t ::= var || app || lam || int || string || add || ...

˜ An AST constructor astt(M) takes |M| + 1 arguments. Tag t specifies the specific AST datatype. The rest is relative to that datatype.

HGMP(λ) = λ-calculus with CTMP and RTMP M ::= x || MN || λx.M || c || M + N || ...

ASTs are the key representation of programs as data. So we add AST constructs for each element of the base language:

˜ M ::= ... || astt(M) t ::= var || app || lam || int || string || add || ...

˜ An AST constructor astt(M) takes |M| + 1 arguments. Tag t specifies the specific AST datatype. The rest is relative to that datatype.

HGMP(λ) = λ-calculus with CTMP and RTMP

We start with the untyped λ-calculus, and CBV. ASTs are the key representation of programs as data. So we add AST constructs for each element of the base language:

˜ M ::= ... || astt(M) t ::= var || app || lam || int || string || add || ...

˜ An AST constructor astt(M) takes |M| + 1 arguments. Tag t specifies the specific AST datatype. The rest is relative to that datatype.

HGMP(λ) = λ-calculus with CTMP and RTMP

We start with the untyped λ-calculus, and CBV.

M ::= x || MN || λx.M || c || M + N || ... ˜ M ::= ... || astt(M) t ::= var || app || lam || int || string || add || ...

˜ An AST constructor astt(M) takes |M| + 1 arguments. Tag t specifies the specific AST datatype. The rest is relative to that datatype.

HGMP(λ) = λ-calculus with CTMP and RTMP

We start with the untyped λ-calculus, and CBV.

M ::= x || MN || λx.M || c || M + N || ...

ASTs are the key representation of programs as data. So we add AST constructs for each element of the base language: ˜ An AST constructor astt(M) takes |M| + 1 arguments. Tag t specifies the specific AST datatype. The rest is relative to that datatype.

HGMP(λ) = λ-calculus with CTMP and RTMP

We start with the untyped λ-calculus, and CBV.

M ::= x || MN || λx.M || c || M + N || ...

ASTs are the key representation of programs as data. So we add AST constructs for each element of the base language:

˜ M ::= ... || astt(M) t ::= var || app || lam || int || string || add || ... HGMP(λ) = λ-calculus with CTMP and RTMP

We start with the untyped λ-calculus, and CBV.

M ::= x || MN || λx.M || c || M + N || ...

ASTs are the key representation of programs as data. So we add AST constructs for each element of the base language:

˜ M ::= ... || astt(M) t ::= var || app || lam || int || string || add || ...

˜ An AST constructor astt(M) takes |M| + 1 arguments. Tag t specifies the specific AST datatype. The rest is relative to that datatype. astvar(”x”) is the AST representation of the variable x

astint(3) is the AST representation of the constant 3

astlam(aststring(”x”), astvar(”x”)) is the AST of λx.x

HGMP(λ): examples astint(3) is the AST representation of the constant 3

astlam(aststring(”x”), astvar(”x”)) is the AST of λx.x

HGMP(λ): examples

astvar(”x”) is the AST representation of the variable x astlam(aststring(”x”), astvar(”x”)) is the AST of λx.x

HGMP(λ): examples

astvar(”x”) is the AST representation of the variable x

astint(3) is the AST representation of the constant 3 HGMP(λ): examples

astvar(”x”) is the AST representation of the variable x

astint(3) is the AST representation of the constant 3

astlam(aststring(”x”), astvar(”x”)) is the AST of λx.x Adding ASTs mirrors the syntax of the language. We make a ’copy’ of the base language.

This is not λ-specific, we’d do the same for any other base.

Notice something? Notice something?

Adding ASTs mirrors the syntax of the language. We make a ’copy’ of the base language.

This is not λ-specific, we’d do the same for any other base. We add downMLs, to indicate compile-time HGMP should occur.

M ::= ... ||↓{M} t ::= ...

Meaning of ↓{M} is

I M must be evaluated (= run) at compile-time

I CT-evaluation of M yields an AST

I AST gets ’spliced into’ the rest of the AST the compiler is constructing

I Compilation proceeds

HGMP(λ): adding CTMP M ::= ... ||↓{M} t ::= ...

Meaning of ↓{M} is

I M must be evaluated (= run) at compile-time

I CT-evaluation of M yields an AST

I AST gets ’spliced into’ the rest of the AST the compiler is constructing

I Compilation proceeds

HGMP(λ): adding CTMP

We add downMLs, to indicate compile-time HGMP should occur. Meaning of ↓{M} is

I M must be evaluated (= run) at compile-time

I CT-evaluation of M yields an AST

I AST gets ’spliced into’ the rest of the AST the compiler is constructing

I Compilation proceeds

HGMP(λ): adding CTMP

We add downMLs, to indicate compile-time HGMP should occur.

M ::= ... ||↓{M} t ::= ... I M must be evaluated (= run) at compile-time

I CT-evaluation of M yields an AST

I AST gets ’spliced into’ the rest of the AST the compiler is constructing

I Compilation proceeds

HGMP(λ): adding CTMP

We add downMLs, to indicate compile-time HGMP should occur.

M ::= ... ||↓{M} t ::= ...

Meaning of ↓{M} is I CT-evaluation of M yields an AST

I AST gets ’spliced into’ the rest of the AST the compiler is constructing

I Compilation proceeds

HGMP(λ): adding CTMP

We add downMLs, to indicate compile-time HGMP should occur.

M ::= ... ||↓{M} t ::= ...

Meaning of ↓{M} is

I M must be evaluated (= run) at compile-time I AST gets ’spliced into’ the rest of the AST the compiler is constructing

I Compilation proceeds

HGMP(λ): adding CTMP

We add downMLs, to indicate compile-time HGMP should occur.

M ::= ... ||↓{M} t ::= ...

Meaning of ↓{M} is

I M must be evaluated (= run) at compile-time

I CT-evaluation of M yields an AST I Compilation proceeds

HGMP(λ): adding CTMP

We add downMLs, to indicate compile-time HGMP should occur.

M ::= ... ||↓{M} t ::= ...

Meaning of ↓{M} is

I M must be evaluated (= run) at compile-time

I CT-evaluation of M yields an AST

I AST gets ’spliced into’ the rest of the AST the compiler is constructing HGMP(λ): adding CTMP

We add downMLs, to indicate compile-time HGMP should occur.

M ::= ... ||↓{M} t ::= ...

Meaning of ↓{M} is

I M must be evaluated (= run) at compile-time

I CT-evaluation of M yields an AST

I AST gets ’spliced into’ the rest of the AST the compiler is constructing

I Compilation proceeds How does ⇓ct work?

I ⇓ct ’searches’ through code for ↓{M} to eliminate them. I For every ↓{M} is found: 0 I M is recursively scanned for downMLs, yielding M 0 I then M is evaluated using ⇓λ, the usual CBV evaluation of λ-calculus, giving an AST A I Then ⇓dl de-ASTifies A, and splice into rest of program

Operational semantics of the foundational calculus

We keep the usual ⇓λ from λ-calculus, but now add a second phase:

M ⇓ct A ⇓λ V | {z } | {z } compile-time run-time I ⇓ct ’searches’ through code for ↓{M} to eliminate them. I For every ↓{M} is found: 0 I M is recursively scanned for downMLs, yielding M 0 I then M is evaluated using ⇓λ, the usual CBV evaluation of λ-calculus, giving an AST A I Then ⇓dl de-ASTifies A, and splice into rest of program

Operational semantics of the foundational calculus

We keep the usual ⇓λ from λ-calculus, but now add a second phase:

M ⇓ct A ⇓λ V | {z } | {z } compile-time run-time

How does ⇓ct work? I For every ↓{M} is found: 0 I M is recursively scanned for downMLs, yielding M 0 I then M is evaluated using ⇓λ, the usual CBV evaluation of λ-calculus, giving an AST A I Then ⇓dl de-ASTifies A, and splice into rest of program

Operational semantics of the foundational calculus

We keep the usual ⇓λ from λ-calculus, but now add a second phase:

M ⇓ct A ⇓λ V | {z } | {z } compile-time run-time

How does ⇓ct work?

I ⇓ct ’searches’ through code for ↓{M} to eliminate them. 0 I M is recursively scanned for downMLs, yielding M 0 I then M is evaluated using ⇓λ, the usual CBV evaluation of λ-calculus, giving an AST A I Then ⇓dl de-ASTifies A, and splice into rest of program

Operational semantics of the foundational calculus

We keep the usual ⇓λ from λ-calculus, but now add a second phase:

M ⇓ct A ⇓λ V | {z } | {z } compile-time run-time

How does ⇓ct work?

I ⇓ct ’searches’ through code for ↓{M} to eliminate them. I For every ↓{M} is found: 0 I then M is evaluated using ⇓λ, the usual CBV evaluation of λ-calculus, giving an AST A I Then ⇓dl de-ASTifies A, and splice into rest of program

Operational semantics of the foundational calculus

We keep the usual ⇓λ from λ-calculus, but now add a second phase:

M ⇓ct A ⇓λ V | {z } | {z } compile-time run-time

How does ⇓ct work?

I ⇓ct ’searches’ through code for ↓{M} to eliminate them. I For every ↓{M} is found: 0 I M is recursively scanned for downMLs, yielding M I Then ⇓dl de-ASTifies A, and splice into rest of program

Operational semantics of the foundational calculus

We keep the usual ⇓λ from λ-calculus, but now add a second phase:

M ⇓ct A ⇓λ V | {z } | {z } compile-time run-time

How does ⇓ct work?

I ⇓ct ’searches’ through code for ↓{M} to eliminate them. I For every ↓{M} is found: 0 I M is recursively scanned for downMLs, yielding M 0 I then M is evaluated using ⇓λ, the usual CBV evaluation of λ-calculus, giving an AST A Operational semantics of the foundational calculus

We keep the usual ⇓λ from λ-calculus, but now add a second phase:

M ⇓ct A ⇓λ V | {z } | {z } compile-time run-time

How does ⇓ct work?

I ⇓ct ’searches’ through code for ↓{M} to eliminate them. I For every ↓{M} is found: 0 I M is recursively scanned for downMLs, yielding M 0 I then M is evaluated using ⇓λ, the usual CBV evaluation of λ-calculus, giving an AST A I Then ⇓dl de-ASTifies A, and splice into rest of program ⇓ct

Idea: ⇓ct scans for ↓{·} and eliminates them by evaluation and splicing.

M ⇓ct AN ⇓ct B M ⇓ct N VARCT APPCT LAMCT x ⇓ct x MN ⇓ct AB λx.M ⇓ct λx.N

M ⇓ct AN ⇓ct B CONSTCT ADDCT c ⇓ct c M + N ⇓ct A + B

Mi ⇓ct Ni M ⇓ct AA ⇓λ BB ⇓dl C ˜ ˜ ASTc CT DOWNML CT astt(M) ⇓ct astt(N) ↓{M} ⇓ct C Note that non-ASTs have no ⇓dl rules, they are stuck.

⇓dl

Idea: ⇓dl removes one layer of ASTs, i.e. goes down a meta-level.

0 0 M ⇓dl M N ⇓dl N VARDL 0 0 APPDL astvar(”x”) ⇓dl x astapp(M, N) ⇓dl M N

0 M ⇓dl ”x” N ⇓dl N 0 LAMDL INTDL astlam(M, N) ⇓dl λx.N astint(n) ⇓dl n

0 0 M ⇓dl M N ⇓dl N STRINGDL 0 0 ADDDL aststring(”x”) ⇓dl ”x” astadd(M, N) ⇓dl M + N ⇓dl

Idea: ⇓dl removes one layer of ASTs, i.e. goes down a meta-level.

0 0 M ⇓dl M N ⇓dl N VARDL 0 0 APPDL astvar(”x”) ⇓dl x astapp(M, N) ⇓dl M N

0 M ⇓dl ”x” N ⇓dl N 0 LAMDL INTDL astlam(M, N) ⇓dl λx.N astint(n) ⇓dl n

0 0 M ⇓dl M N ⇓dl N STRINGDL 0 0 ADDDL aststring(”x”) ⇓dl ”x” astadd(M, N) ⇓dl M + N

Note that non-ASTs have no ⇓dl rules, they are stuck. Our simple calculus intentionally allows variables to be captured dynamically, because strings are not α-converted.

I λx. ↓{astvar(”x”)} ⇓ct λx.x.

I λy. ↓{astvar(”x”)} ⇓ct λy.x.

Scoping I λx. ↓{astvar(”x”)} ⇓ct λx.x.

I λy. ↓{astvar(”x”)} ⇓ct λy.x.

Scoping

Our simple calculus intentionally allows variables to be captured dynamically, because strings are not α-converted. I λy. ↓{astvar(”x”)} ⇓ct λy.x.

Scoping

Our simple calculus intentionally allows variables to be captured dynamically, because strings are not α-converted.

I λx. ↓{astvar(”x”)} ⇓ct λx.x. Scoping

Our simple calculus intentionally allows variables to be captured dynamically, because strings are not α-converted.

I λx. ↓{astvar(”x”)} ⇓ct λx.x.

I λy. ↓{astvar(”x”)} ⇓ct λy.x. It is now easy to add run-time HGMP:

M ::= ... || eval(M) t ::= ... || eval

We add the following rules to ⇓ct , ⇓λ and ⇓dl .

M ⇓ct N M ⇓dl N EVAL CT EVAL DL eval(M) ⇓ct eval(N) asteval(M) ⇓dl eval(N)

0 L ⇓λ MM ⇓dl NN ⇓λ N 0 EVAL RT eval(L) ⇓λ N

Note that eval is not ’disappeared’ at compile-time.

Run-time HGMP M ::= ... || eval(M) t ::= ... || eval

We add the following rules to ⇓ct , ⇓λ and ⇓dl .

M ⇓ct N M ⇓dl N EVAL CT EVAL DL eval(M) ⇓ct eval(N) asteval(M) ⇓dl eval(N)

0 L ⇓λ MM ⇓dl NN ⇓λ N 0 EVAL RT eval(L) ⇓λ N

Note that eval is not ’disappeared’ at compile-time.

Run-time HGMP

It is now easy to add run-time HGMP: We add the following rules to ⇓ct , ⇓λ and ⇓dl .

M ⇓ct N M ⇓dl N EVAL CT EVAL DL eval(M) ⇓ct eval(N) asteval(M) ⇓dl eval(N)

0 L ⇓λ MM ⇓dl NN ⇓λ N 0 EVAL RT eval(L) ⇓λ N

Note that eval is not ’disappeared’ at compile-time.

Run-time HGMP

It is now easy to add run-time HGMP:

M ::= ... || eval(M) t ::= ... || eval M ⇓ct N M ⇓dl N EVAL CT EVAL DL eval(M) ⇓ct eval(N) asteval(M) ⇓dl eval(N)

0 L ⇓λ MM ⇓dl NN ⇓λ N 0 EVAL RT eval(L) ⇓λ N

Note that eval is not ’disappeared’ at compile-time.

Run-time HGMP

It is now easy to add run-time HGMP:

M ::= ... || eval(M) t ::= ... || eval

We add the following rules to ⇓ct , ⇓λ and ⇓dl . Note that eval is not ’disappeared’ at compile-time.

Run-time HGMP

It is now easy to add run-time HGMP:

M ::= ... || eval(M) t ::= ... || eval

We add the following rules to ⇓ct , ⇓λ and ⇓dl .

M ⇓ct N M ⇓dl N EVAL CT EVAL DL eval(M) ⇓ct eval(N) asteval(M) ⇓dl eval(N)

0 L ⇓λ MM ⇓dl NN ⇓λ N 0 EVAL RT eval(L) ⇓λ N Run-time HGMP

It is now easy to add run-time HGMP:

M ::= ... || eval(M) t ::= ... || eval

We add the following rules to ⇓ct , ⇓λ and ⇓dl .

M ⇓ct N M ⇓dl N EVAL CT EVAL DL eval(M) ⇓ct eval(N) asteval(M) ⇓dl eval(N)

0 L ⇓λ MM ⇓dl NN ⇓λ N 0 EVAL RT eval(L) ⇓λ N

Note that eval is not ’disappeared’ at compile-time. What about e.g. ↓{↓{M}}, i.e. meta-meta-programming?

Calculus so far doesn’t allow the representation of ASTs as ASTs.

This can be handled in several ways, we ’internalise’ tags:

M ::= ... || tagt t ::= ... || promote

˜ Hence AST datatype astpromote(M, N) which allows an arbitrary AST with a tag M and N˜ to be promoted up a meta-level. Promoted ASTs can then be reduced one meta-level with the existing ⇓dl relation. E.g.:

astpromote(string, aststring(”x”)) ⇓dl aststring(”x”)

Enriching the calculus: higher-order ASTs Calculus so far doesn’t allow the representation of ASTs as ASTs.

This can be handled in several ways, we ’internalise’ tags:

M ::= ... || tagt t ::= ... || promote

˜ Hence AST datatype astpromote(M, N) which allows an arbitrary AST with a tag M and parameters N˜ to be promoted up a meta-level. Promoted ASTs can then be reduced one meta-level with the existing ⇓dl relation. E.g.:

astpromote(string, aststring(”x”)) ⇓dl aststring(”x”)

Enriching the calculus: higher-order ASTs What about e.g. ↓{↓{M}}, i.e. meta-meta-programming? This can be handled in several ways, we ’internalise’ tags:

M ::= ... || tagt t ::= ... || promote

˜ Hence AST datatype astpromote(M, N) which allows an arbitrary AST with a tag M and parameters N˜ to be promoted up a meta-level. Promoted ASTs can then be reduced one meta-level with the existing ⇓dl relation. E.g.:

astpromote(string, aststring(”x”)) ⇓dl aststring(”x”)

Enriching the calculus: higher-order ASTs What about e.g. ↓{↓{M}}, i.e. meta-meta-programming?

Calculus so far doesn’t allow the representation of ASTs as ASTs. M ::= ... || tagt t ::= ... || promote

˜ Hence AST datatype astpromote(M, N) which allows an arbitrary AST with a tag M and parameters N˜ to be promoted up a meta-level. Promoted ASTs can then be reduced one meta-level with the existing ⇓dl relation. E.g.:

astpromote(string, aststring(”x”)) ⇓dl aststring(”x”)

Enriching the calculus: higher-order ASTs What about e.g. ↓{↓{M}}, i.e. meta-meta-programming?

Calculus so far doesn’t allow the representation of ASTs as ASTs.

This can be handled in several ways, we ’internalise’ tags: astpromote(string, aststring(”x”)) ⇓dl aststring(”x”)

Enriching the calculus: higher-order ASTs What about e.g. ↓{↓{M}}, i.e. meta-meta-programming?

Calculus so far doesn’t allow the representation of ASTs as ASTs.

This can be handled in several ways, we ’internalise’ tags:

M ::= ... || tagt t ::= ... || promote

˜ Hence AST datatype astpromote(M, N) which allows an arbitrary AST with a tag M and parameters N˜ to be promoted up a meta-level. Promoted ASTs can then be reduced one meta-level with the existing ⇓dl relation. E.g.: Enriching the calculus: higher-order ASTs What about e.g. ↓{↓{M}}, i.e. meta-meta-programming?

Calculus so far doesn’t allow the representation of ASTs as ASTs.

This can be handled in several ways, we ’internalise’ tags:

M ::= ... || tagt t ::= ... || promote

˜ Hence AST datatype astpromote(M, N) which allows an arbitrary AST with a tag M and parameters N˜ to be promoted up a meta-level. Promoted ASTs can then be reduced one meta-level with the existing ⇓dl relation. E.g.:

astpromote(string, aststring(”x”)) ⇓dl aststring(”x”) PROMOTE TAG tagt ⇓dl tagt

L ⇓dl tagt t 6= promote ... Mi ⇓dl Ni ... ˜ ˜ PROMOTEDL 1 astpromote(L, M) ⇓dl astt(N)

0 L ⇓dl tagpromote M ⇓dl tagt ... Ni ⇓dl Ni ... PROMOTEDL 2 ˜ ˜0 astpromote(L, M, N) ⇓dl astpromote(tagt, N )

⇓λ and ⇓ct are unchanged as rules, but work on larger set of programs.

Operational semantics of higher-order ASTs Operational semantics of higher-order ASTs

PROMOTE TAG tagt ⇓dl tagt

L ⇓dl tagt t 6= promote ... Mi ⇓dl Ni ... ˜ ˜ PROMOTEDL 1 astpromote(L, M) ⇓dl astt(N)

0 L ⇓dl tagpromote M ⇓dl tagt ... Ni ⇓dl Ni ... PROMOTEDL 2 ˜ ˜0 astpromote(L, M, N) ⇓dl astpromote(tagt, N )

⇓λ and ⇓ct are unchanged as rules, but work on larger set of programs. UpMLs (aka quasi-quotes)

We have now finished, and obtained a λ-calculus with CTMP and RTMP. ASTs are the cornerstone of our calculus. But ASTs are verbose. UpMLs (aka quasi-quotes or back-quotes) ameliorate this problem by allowing concrete syntax to be used to represent ASTs.

To add UpMLs to our language, we first extend the grammar as follows: M ::= ... ||↑{M} t ::= ...

We model upMLs as “syntactic-sugar” to be removed at compile-time by conversion to ASTs, e.g.

↑{2} ⇓ct astint(2)

Like downMLs, upMLs are disappeared by the compile-time stage.

UpMLs (aka quasi-quotes) To add UpMLs to our language, we first extend the grammar as follows: M ::= ... ||↑{M} t ::= ...

We model upMLs as “syntactic-sugar” to be removed at compile-time by conversion to ASTs, e.g.

↑{2} ⇓ct astint(2)

Like downMLs, upMLs are disappeared by the compile-time stage.

UpMLs (aka quasi-quotes) ASTs are the cornerstone of our calculus. But ASTs are verbose. UpMLs (aka quasi-quotes or back-quotes) ameliorate this problem by allowing concrete syntax to be used to represent ASTs. M ::= ... ||↑{M} t ::= ...

We model upMLs as “syntactic-sugar” to be removed at compile-time by conversion to ASTs, e.g.

↑{2} ⇓ct astint(2)

Like downMLs, upMLs are disappeared by the compile-time stage.

UpMLs (aka quasi-quotes) ASTs are the cornerstone of our calculus. But ASTs are verbose. UpMLs (aka quasi-quotes or back-quotes) ameliorate this problem by allowing concrete syntax to be used to represent ASTs.

To add UpMLs to our language, we first extend the grammar as follows: We model upMLs as “syntactic-sugar” to be removed at compile-time by conversion to ASTs, e.g.

↑{2} ⇓ct astint(2)

Like downMLs, upMLs are disappeared by the compile-time stage.

UpMLs (aka quasi-quotes) ASTs are the cornerstone of our calculus. But ASTs are verbose. UpMLs (aka quasi-quotes or back-quotes) ameliorate this problem by allowing concrete syntax to be used to represent ASTs.

To add UpMLs to our language, we first extend the grammar as follows: M ::= ... ||↑{M} t ::= ... Like downMLs, upMLs are disappeared by the compile-time stage.

UpMLs (aka quasi-quotes) ASTs are the cornerstone of our calculus. But ASTs are verbose. UpMLs (aka quasi-quotes or back-quotes) ameliorate this problem by allowing concrete syntax to be used to represent ASTs.

To add UpMLs to our language, we first extend the grammar as follows: M ::= ... ||↑{M} t ::= ...

We model upMLs as “syntactic-sugar” to be removed at compile-time by conversion to ASTs, e.g.

↑{2} ⇓ct astint(2) UpMLs (aka quasi-quotes) ASTs are the cornerstone of our calculus. But ASTs are verbose. UpMLs (aka quasi-quotes or back-quotes) ameliorate this problem by allowing concrete syntax to be used to represent ASTs.

To add UpMLs to our language, we first extend the grammar as follows: M ::= ... ||↑{M} t ::= ...

We model upMLs as “syntactic-sugar” to be removed at compile-time by conversion to ASTs, e.g.

↑{2} ⇓ct astint(2)

Like downMLs, upMLs are disappeared by the compile-time stage. Recall, we want quasi-quotes, not quotes to be more flexible. I.e. we want ’holes’ in upMLs where we can run arbitrary computation. How can we do that?

Let’s reuse ↓{·}!

A downML ↓{·} inside ↑{... ↓{M}...} is a ’hole’ where arbitrary computation can be executed to produce an AST. This AST is then used as is. For example:

↑{2+ ↓{astint(7)}} ⇓ct astadd(astint(2), astint(7))

↑{2+ ↓{↑{3 + 4}}} ⇓ct astadd(astint(2), astadd(astint(3), astint(4)))

A subtlety Let’s reuse ↓{·}!

A downML ↓{·} inside ↑{... ↓{M}...} is a ’hole’ where arbitrary computation can be executed to produce an AST. This AST is then used as is. For example:

↑{2+ ↓{astint(7)}} ⇓ct astadd(astint(2), astint(7))

↑{2+ ↓{↑{3 + 4}}} ⇓ct astadd(astint(2), astadd(astint(3), astint(4)))

A subtlety Recall, we want quasi-quotes, not quotes to be more flexible. I.e. we want ’holes’ in upMLs where we can run arbitrary computation. How can we do that? Let’s reuse ↓{·}!

A downML ↓{·} inside ↑{... ↓{M}...} is a ’hole’ where arbitrary computation can be executed to produce an AST. This AST is then used as is. For example:

↑{2+ ↓{astint(7)}} ⇓ct astadd(astint(2), astint(7))

↑{2+ ↓{↑{3 + 4}}} ⇓ct astadd(astint(2), astadd(astint(3), astint(4)))

A subtlety Recall, we want quasi-quotes, not quotes to be more flexible. I.e. we want ’holes’ in upMLs where we can run arbitrary computation. How can we do that? A downML ↓{·} inside ↑{... ↓{M}...} is a ’hole’ where arbitrary computation can be executed to produce an AST. This AST is then used as is. For example:

↑{2+ ↓{astint(7)}} ⇓ct astadd(astint(2), astint(7))

↑{2+ ↓{↑{3 + 4}}} ⇓ct astadd(astint(2), astadd(astint(3), astint(4)))

A subtlety Recall, we want quasi-quotes, not quotes to be more flexible. I.e. we want ’holes’ in upMLs where we can run arbitrary computation. How can we do that?

Let’s reuse ↓{·}! A subtlety Recall, we want quasi-quotes, not quotes to be more flexible. I.e. we want ’holes’ in upMLs where we can run arbitrary computation. How can we do that?

Let’s reuse ↓{·}!

A downML ↓{·} inside ↑{... ↓{M}...} is a ’hole’ where arbitrary computation can be executed to produce an AST. This AST is then used as is. For example:

↑{2+ ↓{astint(7)}} ⇓ct astadd(astint(2), astint(7))

↑{2+ ↓{↑{3 + 4}}} ⇓ct astadd(astint(2), astadd(astint(3), astint(4))) Operational semantics for ↑{M}

We introduce a new reduction relation ⇓ul :

M ⇓ul A M ⇓ct A UPML CT DOWNML UL ↑{M} ⇓ct A ↓{M} ⇓ul A

M ⇓ul AN ⇓ul B STRINGUL APPUL ”x” ⇓ul aststring(”x”) MN ⇓ul astapp(A, B)

M ⇓ul A LAMUL TAGUL λx.M ⇓ul astlam(aststring(”x”), A) tagt ⇓ul tagt

M ⇓ul A M ⇓ul AA ⇓ul B EVAL UL UPML UL eval(M) ⇓ul asteval(A) ↑{M} ⇓ul B

... Mi ⇓ul Ai ... x ⇓ ast (”x”) VARUL ˜ ˜ ASTUL ul var astt(M) ⇓ul astpromote(tagt, A) I ↑{·} goes up one meta-level (= adds a layer of ASTs).

I ↓{·} goes down one meta-level (= removes a layer of ASTs).

Thus RT-HGMP and CT-HGMP are neatly connected as two facets of the same AST-coin.

The rules capture our intuitions Thus RT-HGMP and CT-HGMP are neatly connected as two facets of the same AST-coin.

The rules capture our intuitions

I ↑{·} goes up one meta-level (= adds a layer of ASTs).

I ↓{·} goes down one meta-level (= removes a layer of ASTs). The rules capture our intuitions

I ↑{·} goes up one meta-level (= adds a layer of ASTs).

I ↓{·} goes down one meta-level (= removes a layer of ASTs).

Thus RT-HGMP and CT-HGMP are neatly connected as two facets of the same AST-coin. We can easily add other features, like

I Lifting, where semi-arbitrary run-time values to be lifted up a meta-level, e.g. lift(3) ⇓λ astint(3). I Cross-level variable scoping.

Other features I Lifting, where semi-arbitrary run-time values to be lifted up a meta-level, e.g. lift(3) ⇓λ astint(3). I Cross-level variable scoping.

Other features

We can easily add other features, like I Cross-level variable scoping.

Other features

We can easily add other features, like

I Lifting, where semi-arbitrary run-time values to be lifted up a meta-level, e.g. lift(3) ⇓λ astint(3). Other features

We can easily add other features, like

I Lifting, where semi-arbitrary run-time values to be lifted up a meta-level, e.g. lift(3) ⇓λ astint(3). I Cross-level variable scoping. We want to specialise λnx.xn w.r.t. first argument.

M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}}

Then power 3 reduces to AST equivalent of

↑{λx.x × x × x}

The function power can be used to specialise code at compile-time:

let cube = ↓{power 3} in (cube 4) + (cube 5)

and at run-time:

let cube = eval(power 3) in (cube 4) + (cube 5)

Staged power function λnx.x n M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}}

Then power 3 reduces to AST equivalent of

↑{λx.x × x × x}

The function power can be used to specialise code at compile-time:

let cube = ↓{power 3} in (cube 4) + (cube 5)

and at run-time:

let cube = eval(power 3) in (cube 4) + (cube 5)

Staged power function λnx.x n We want to specialise λnx.xn w.r.t. first argument. Then power 3 reduces to AST equivalent of

↑{λx.x × x × x}

The function power can be used to specialise code at compile-time:

let cube = ↓{power 3} in (cube 4) + (cube 5)

and at run-time:

let cube = eval(power 3) in (cube 4) + (cube 5)

Staged power function λnx.x n We want to specialise λnx.xn w.r.t. first argument.

M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}} The function power can be used to specialise code at compile-time:

let cube = ↓{power 3} in (cube 4) + (cube 5)

and at run-time:

let cube = eval(power 3) in (cube 4) + (cube 5)

Staged power function λnx.x n We want to specialise λnx.xn w.r.t. first argument.

M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}}

Then power 3 reduces to AST equivalent of

↑{λx.x × x × x} let cube = ↓{power 3} in (cube 4) + (cube 5)

and at run-time:

let cube = eval(power 3) in (cube 4) + (cube 5)

Staged power function λnx.x n We want to specialise λnx.xn w.r.t. first argument.

M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}}

Then power 3 reduces to AST equivalent of

↑{λx.x × x × x}

The function power can be used to specialise code at compile-time: and at run-time:

let cube = eval(power 3) in (cube 4) + (cube 5)

Staged power function λnx.x n We want to specialise λnx.xn w.r.t. first argument.

M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}}

Then power 3 reduces to AST equivalent of

↑{λx.x × x × x}

The function power can be used to specialise code at compile-time:

let cube = ↓{power 3} in (cube 4) + (cube 5) let cube = eval(power 3) in (cube 4) + (cube 5)

Staged power function λnx.x n We want to specialise λnx.xn w.r.t. first argument.

M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}}

Then power 3 reduces to AST equivalent of

↑{λx.x × x × x}

The function power can be used to specialise code at compile-time:

let cube = ↓{power 3} in (cube 4) + (cube 5)

and at run-time: Staged power function λnx.x n We want to specialise λnx.xn w.r.t. first argument.

M = rec p.λn.if n = 1 then ↑{x} else ↑{x ×↓{p (n − 1)}} power = λn. ↑{λx. ↓{M n}}

Then power 3 reduces to AST equivalent of

↑{λx.x × x × x}

The function power can be used to specialise code at compile-time:

let cube = ↓{power 3} in (cube 4) + (cube 5)

and at run-time:

let cube = eval(power 3) in (cube 4) + (cube 5) We believe that adding HGMP to λ-calculus is simple, yet captures the essence of HGMP.

How do we prove this, when existing approaches to HGMP diverge from our proposals?

Reflective equilibrium, balance or coherence between model and PL reality.

If you have HGMP phenomena that don’t agree with our calculus, please contact us.

Rational reconstruction? How do we prove this, when existing approaches to HGMP diverge from our proposals?

Reflective equilibrium, balance or coherence between model and PL reality.

If you have HGMP phenomena that don’t agree with our calculus, please contact us.

Rational reconstruction?

We believe that adding HGMP to λ-calculus is simple, yet captures the essence of HGMP. Reflective equilibrium, balance or coherence between model and PL reality.

If you have HGMP phenomena that don’t agree with our calculus, please contact us.

Rational reconstruction?

We believe that adding HGMP to λ-calculus is simple, yet captures the essence of HGMP.

How do we prove this, when existing approaches to HGMP diverge from our proposals? If you have HGMP phenomena that don’t agree with our calculus, please contact us.

Rational reconstruction?

We believe that adding HGMP to λ-calculus is simple, yet captures the essence of HGMP.

How do we prove this, when existing approaches to HGMP diverge from our proposals?

Reflective equilibrium, balance or coherence between model and PL reality. Rational reconstruction?

We believe that adding HGMP to λ-calculus is simple, yet captures the essence of HGMP.

How do we prove this, when existing approaches to HGMP diverge from our proposals?

Reflective equilibrium, balance or coherence between model and PL reality.

If you have HGMP phenomena that don’t agree with our calculus, please contact us. Nothing in the HGMPification of λ-calculus depended on λ-calculus being the source language. The process was completely generic.

HGMP(·): mechanical HGMPification of languages HGMP(·): mechanical HGMPification of languages

Nothing in the HGMPification of λ-calculus depended on λ-calculus being the source language. The process was completely generic. We seek to extend L with HGMP features to create Lmp . We can then create Lmp as follows:

I Mirror every syntactic element of L with an AST and a tag.

I Add eval and tags eval and promote.

I Add ↑{·} and ↓{·}.

That gives us the syntax of Lmp . Operational semantics:

Add appropriate reduction rules for ASTs, upMLs and downMLs with computation driven by the base language. Note that HGMP(λ) does not change the reduction rules of λ-calculus itself. Only adds rules.

HGMP(·) I Mirror every syntactic element of L with an AST and a tag.

I Add eval and tags eval and promote.

I Add ↑{·} and ↓{·}.

That gives us the syntax of Lmp . Operational semantics:

Add appropriate reduction rules for ASTs, upMLs and downMLs with computation driven by the base language. Note that HGMP(λ) does not change the reduction rules of λ-calculus itself. Only adds rules.

HGMP(·)

We seek to extend L with HGMP features to create Lmp . We can then create Lmp as follows: I Add eval and tags eval and promote.

I Add ↑{·} and ↓{·}.

That gives us the syntax of Lmp . Operational semantics:

Add appropriate reduction rules for ASTs, upMLs and downMLs with computation driven by the base language. Note that HGMP(λ) does not change the reduction rules of λ-calculus itself. Only adds rules.

HGMP(·)

We seek to extend L with HGMP features to create Lmp . We can then create Lmp as follows:

I Mirror every syntactic element of L with an AST and a tag. I Add ↑{·} and ↓{·}.

That gives us the syntax of Lmp . Operational semantics:

Add appropriate reduction rules for ASTs, upMLs and downMLs with computation driven by the base language. Note that HGMP(λ) does not change the reduction rules of λ-calculus itself. Only adds rules.

HGMP(·)

We seek to extend L with HGMP features to create Lmp . We can then create Lmp as follows:

I Mirror every syntactic element of L with an AST and a tag.

I Add eval and tags eval and promote. That gives us the syntax of Lmp . Operational semantics:

Add appropriate reduction rules for ASTs, upMLs and downMLs with computation driven by the base language. Note that HGMP(λ) does not change the reduction rules of λ-calculus itself. Only adds rules.

HGMP(·)

We seek to extend L with HGMP features to create Lmp . We can then create Lmp as follows:

I Mirror every syntactic element of L with an AST and a tag.

I Add eval and tags eval and promote.

I Add ↑{·} and ↓{·}. Add appropriate reduction rules for ASTs, upMLs and downMLs with computation driven by the base language. Note that HGMP(λ) does not change the reduction rules of λ-calculus itself. Only adds rules.

HGMP(·)

We seek to extend L with HGMP features to create Lmp . We can then create Lmp as follows:

I Mirror every syntactic element of L with an AST and a tag.

I Add eval and tags eval and promote.

I Add ↑{·} and ↓{·}.

That gives us the syntax of Lmp . Operational semantics: HGMP(·)

We seek to extend L with HGMP features to create Lmp . We can then create Lmp as follows:

I Mirror every syntactic element of L with an AST and a tag.

I Add eval and tags eval and promote.

I Add ↑{·} and ↓{·}.

That gives us the syntax of Lmp . Operational semantics:

Add appropriate reduction rules for ASTs, upMLs and downMLs with computation driven by the base language. Note that HGMP(λ) does not change the reduction rules of λ-calculus itself. Only adds rules. Assume C is the set of L ’s program constructors, Lmp’s constructors and tags then:

T = C ∪ {eval, promote}

Cmp = C ∪ {eval, ↓{_}, ↑{_}} ∪ {astt | t ∈ T } ∪ {tagt | t ∈ T }

The and binders of the new syntax are as follows:

I If c ∈ C then its and binders are unchanged in Cmp.

I astc has the same arity as c ∈ C and no binders.

I astpromote has variable arity, or, equivalently has arity 2, with the second argument being of type list. There are no binders.

I asteval has arity 1 and no binders.

I tagt has arity 0 and no binders for t ∈ T . I eval, ↓{_}, and ↑{_} have arity 1 and no binders.

HGMP(·) semi-formally The arities and binders of the new syntax are as follows:

I If c ∈ C then its arity and binders are unchanged in Cmp.

I astc has the same arity as c ∈ C and no binders.

I astpromote has variable arity, or, equivalently has arity 2, with the second argument being of type list. There are no binders.

I asteval has arity 1 and no binders.

I tagt has arity 0 and no binders for t ∈ T . I eval, ↓{_}, and ↑{_} have arity 1 and no binders.

HGMP(·) semi-formally

Assume C is the set of L ’s program constructors, Lmp’s constructors and tags then:

T = C ∪ {eval, promote}

Cmp = C ∪ {eval, ↓{_}, ↑{_}} ∪ {astt | t ∈ T } ∪ {tagt | t ∈ T } HGMP(·) semi-formally

Assume C is the set of L ’s program constructors, Lmp’s constructors and tags then:

T = C ∪ {eval, promote}

Cmp = C ∪ {eval, ↓{_}, ↑{_}} ∪ {astt | t ∈ T } ∪ {tagt | t ∈ T }

The arities and binders of the new syntax are as follows:

I If c ∈ C then its arity and binders are unchanged in Cmp.

I astc has the same arity as c ∈ C and no binders.

I astpromote has variable arity, or, equivalently has arity 2, with the second argument being of type list. There are no binders.

I asteval has arity 1 and no binders.

I tagt has arity 0 and no binders for t ∈ T . I eval, ↓{_}, and ↑{_} have arity 1 and no binders. We add the following rules to the operations rules of L (omitting rules for upML for simplicity).

0 t ∈ T L ⇓λ MM ⇓dl NN ⇓λ N 0 t ⇓λ t eval(L) ⇓λ N

... Mi ⇓λ Ni ... t ∈ T ˜ ˜ astt(M) ⇓λ astt(N)

Constructors with binders are most easily explained by example. If c has arity 2, with the first argument being a binder, the following rule must be added:

0 M ⇓dl ”x” N ⇓dl N 0 astc(M, N) ⇓dl c(x, N )

HGMP(·) Constructors with binders are most easily explained by example. If c has arity 2, with the first argument being a binder, the following rule must be added:

0 M ⇓dl ”x” N ⇓dl N 0 astc(M, N) ⇓dl c(x, N )

HGMP(·)

We add the following rules to the operations rules of L (omitting rules for upML for simplicity).

0 t ∈ T L ⇓λ MM ⇓dl NN ⇓λ N 0 t ⇓λ t eval(L) ⇓λ N

... Mi ⇓λ Ni ... t ∈ T ˜ ˜ astt(M) ⇓λ astt(N) HGMP(·)

We add the following rules to the operations rules of L (omitting rules for upML for simplicity).

0 t ∈ T L ⇓λ MM ⇓dl NN ⇓λ N 0 t ⇓λ t eval(L) ⇓λ N

... Mi ⇓λ Ni ... t ∈ T ˜ ˜ astt(M) ⇓λ astt(N)

Constructors with binders are most easily explained by example. If c has arity 2, with the first argument being a binder, the following rule must be added:

0 M ⇓dl ”x” N ⇓dl N 0 astc(M, N) ⇓dl c(x, N ) L ⇓dl tagt Mi ⇓dl Ni t ∈ T ˜ ˜ astpromote(L, M) ⇓dl astc(N)

L ⇓dl tagpromote M ⇓dl tagt Ni ⇓dl Ri t ∈ T ˜ ˜ tag ⇓ tag astpromote(L, M, N) ⇓dl astpromote(tagt, R) t dl t

HGMP(·)

The following rules must be added for higher-order ASTs: HGMP(·)

The following rules must be added for higher-order ASTs:

L ⇓dl tagt Mi ⇓dl Ni t ∈ T ˜ ˜ astpromote(L, M) ⇓dl astc(N)

L ⇓dl tagpromote M ⇓dl tagt Ni ⇓dl Ri t ∈ T ˜ ˜ tag ⇓ tag astpromote(L, M, N) ⇓dl astpromote(tagt, R) t dl t HGMP(·)

Assuming we wish to enable compile-time HGMP, a ⇓ct relation must be added:

M ∈ {x, ”x”} ∪ {tagt | t ∈ T } M ⇓ct N M ⇓ct M eval(M) ⇓ct eval(N)

Mi ⇓ct Ni c ∈ C Mi ⇓ct Ni t ∈ T ˜ ˜ ˜ ˜ c(M) ⇓ct c(N) astt(M) ⇓ct astt(N)

t ∈ T M ⇓ct AA ⇓λ BB ⇓dl C tagt ⇓ct tagt ↓{M} ⇓ct C I What’s a good formal way of specifying source and target languages of HGMP(·)?

I What does it mean for HGMP(·) to be correct?

I Relationship HGMP(L) and HGMP(HGMP(L))?

I What interesting properties does HGMP(·) preserve?

I What languages or language features cannot be handled satisfactorily by HGMP(.)?

Questions about HGMP(·) I What does it mean for HGMP(·) to be correct?

I Relationship HGMP(L) and HGMP(HGMP(L))?

I What interesting properties does HGMP(·) preserve?

I What languages or language features cannot be handled satisfactorily by HGMP(.)?

Questions about HGMP(·)

I What’s a good formal way of specifying source and target languages of HGMP(·)? I Relationship HGMP(L) and HGMP(HGMP(L))?

I What interesting properties does HGMP(·) preserve?

I What languages or language features cannot be handled satisfactorily by HGMP(.)?

Questions about HGMP(·)

I What’s a good formal way of specifying source and target languages of HGMP(·)?

I What does it mean for HGMP(·) to be correct? I What interesting properties does HGMP(·) preserve?

I What languages or language features cannot be handled satisfactorily by HGMP(.)?

Questions about HGMP(·)

I What’s a good formal way of specifying source and target languages of HGMP(·)?

I What does it mean for HGMP(·) to be correct?

I Relationship HGMP(L) and HGMP(HGMP(L))? I What languages or language features cannot be handled satisfactorily by HGMP(.)?

Questions about HGMP(·)

I What’s a good formal way of specifying source and target languages of HGMP(·)?

I What does it mean for HGMP(·) to be correct?

I Relationship HGMP(L) and HGMP(HGMP(L))?

I What interesting properties does HGMP(·) preserve? Questions about HGMP(·)

I What’s a good formal way of specifying source and target languages of HGMP(·)?

I What does it mean for HGMP(·) to be correct?

I Relationship HGMP(L) and HGMP(HGMP(L))?

I What interesting properties does HGMP(·) preserve?

I What languages or language features cannot be handled satisfactorily by HGMP(.)? HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains. I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)? I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques? I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell? I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages? I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics? I Generalising HGMP(·) to heterogeneous meta-programming?

Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)? Conclusion HGMP(·) gives a foundational approach to meta-programming. Much work remains.

I Compiler-hooks for HGMP(·)?

I Adding hygiene, e.g. using nominal techniques?

I Extension of HGMP(·) to typed base-languages, using staged typing a la Template Haskell?

I Implementation of HGMP(·) and applying it to real languages?

I Application to proof assistants, e.g. “Engineering Proof by Reflection in Agda” by Swierstra et al to implement tactics?

I Hoare logics and other specification mechanism. Can HGMP(·) be extended to transform logic for L to logic for HGMP(L)?

I Generalising HGMP(·) to heterogeneous meta-programming? Questions?