c75517ac79
Adds `Term::Seq { lhs, rhs }` (serde tag "seq") as a first-class
AST node for sequencing effectful expressions. Equivalent in
behaviour to `let _ = lhs in rhs`, but the dedicated node gives the
pretty-printer and diagnostics a cleaner shape and surfaces the
intent ("run for effect, then yield rhs") to future tooling.
Typecheck: lhs must be Unit; rhs's type is the result; effects
accumulate.
Codegen: lower lhs (drop SSA), lower rhs (return).
Capture / deps walkers: recurse into both sides.
Refactored examples/list_map.ail.json's print_list to use seq
instead of `let _ = ...`. Output unchanged (2/4/6).
Hash stability: existing examples without Term::Seq serialise
bit-identical; only list_map.ail.json's hashes changed (deliberate
refactor).
Tests: 51 green (was 50). New unit test
`ailang_check::tests::seq_lhs_must_be_unit` covers the type-error
path; existing list_map e2e covers the happy path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
207 lines
5.4 KiB
JSON
207 lines
5.4 KiB
JSON
{
|
|
"schema": "ailang/v0",
|
|
"name": "list_map",
|
|
"imports": [],
|
|
"defs": [
|
|
{
|
|
"kind": "type",
|
|
"name": "IntList",
|
|
"doc": "Singly-linked list of Int, boxed.",
|
|
"ctors": [
|
|
{ "name": "Nil", "fields": [] },
|
|
{
|
|
"name": "Cons",
|
|
"fields": [
|
|
{ "k": "con", "name": "Int" },
|
|
{ "k": "con", "name": "IntList" }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "map_int",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [
|
|
{
|
|
"k": "fn",
|
|
"params": [{ "k": "con", "name": "Int" }],
|
|
"ret": { "k": "con", "name": "Int" },
|
|
"effects": []
|
|
},
|
|
{ "k": "con", "name": "IntList" }
|
|
],
|
|
"ret": { "k": "con", "name": "IntList" },
|
|
"effects": []
|
|
},
|
|
"params": ["f", "xs"],
|
|
"doc": "Apply f to every element. Recursive on the tail.",
|
|
"body": {
|
|
"t": "match",
|
|
"scrutinee": { "t": "var", "name": "xs" },
|
|
"arms": [
|
|
{
|
|
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
|
"body": {
|
|
"t": "ctor",
|
|
"type": "IntList",
|
|
"ctor": "Nil",
|
|
"args": []
|
|
}
|
|
},
|
|
{
|
|
"pat": {
|
|
"p": "ctor",
|
|
"ctor": "Cons",
|
|
"fields": [
|
|
{ "p": "var", "name": "h" },
|
|
{ "p": "var", "name": "t" }
|
|
]
|
|
},
|
|
"body": {
|
|
"t": "ctor",
|
|
"type": "IntList",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "f" },
|
|
"args": [{ "t": "var", "name": "h" }]
|
|
},
|
|
{
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "map_int" },
|
|
"args": [
|
|
{ "t": "var", "name": "f" },
|
|
{ "t": "var", "name": "t" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "print_list",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [{ "k": "con", "name": "IntList" }],
|
|
"ret": { "k": "con", "name": "Unit" },
|
|
"effects": ["IO"]
|
|
},
|
|
"params": ["xs"],
|
|
"doc": "Print each Int on its own line.",
|
|
"body": {
|
|
"t": "match",
|
|
"scrutinee": { "t": "var", "name": "xs" },
|
|
"arms": [
|
|
{
|
|
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
|
"body": { "t": "lit", "lit": { "kind": "unit" } }
|
|
},
|
|
{
|
|
"pat": {
|
|
"p": "ctor",
|
|
"ctor": "Cons",
|
|
"fields": [
|
|
{ "p": "var", "name": "h" },
|
|
{ "p": "var", "name": "t" }
|
|
]
|
|
},
|
|
"body": {
|
|
"t": "seq",
|
|
"lhs": {
|
|
"t": "do",
|
|
"op": "io/print_int",
|
|
"args": [{ "t": "var", "name": "h" }]
|
|
},
|
|
"rhs": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "print_list" },
|
|
"args": [{ "t": "var", "name": "t" }]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "main",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [],
|
|
"ret": { "k": "con", "name": "Unit" },
|
|
"effects": ["IO"]
|
|
},
|
|
"params": [],
|
|
"doc": "Build [1,2,3], double each, print result.",
|
|
"body": {
|
|
"t": "let",
|
|
"name": "xs",
|
|
"value": {
|
|
"t": "ctor",
|
|
"type": "IntList",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
|
|
{
|
|
"t": "ctor",
|
|
"type": "IntList",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 2 } },
|
|
{
|
|
"t": "ctor",
|
|
"type": "IntList",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
|
|
{
|
|
"t": "ctor",
|
|
"type": "IntList",
|
|
"ctor": "Nil",
|
|
"args": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"body": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "print_list" },
|
|
"args": [
|
|
{
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "map_int" },
|
|
"args": [
|
|
{
|
|
"t": "lam",
|
|
"params": ["x"],
|
|
"paramTypes": [{ "k": "con", "name": "Int" }],
|
|
"retType": { "k": "con", "name": "Int" },
|
|
"effects": [],
|
|
"body": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "*" },
|
|
"args": [
|
|
{ "t": "var", "name": "x" },
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 2 } }
|
|
]
|
|
}
|
|
},
|
|
{ "t": "var", "name": "xs" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|