Add support for first-class functions in expressions
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 12.4k
- Forks
- 2.4k
- PR merge metrics
- No merged PRs in 30d
Description
We've now seen two cases where first-class functions would make sense:
- Referencing capture groups in a regular expression
replaceoperation (see https://github.com/mapbox/mapbox-gl-js/pull/6228#issuecomment-372474532) - Providing a
reducefunction for aggregating feature properties on clustered data (https://github.com/mapbox/mapbox-gl-js/pull/7004)
Let's explore adding function types to the expression language and a syntax for defining (and applying?) function values. Initial proposal to get things started:
A function value is defined with ["fn", "a", "b", "c", (etc.), function_body_expression], where a, b, c, ... are parameter names, and function_expression is an expression that may include ["var", paramter_name] expressions to reference parameter values. There is no way to explicitly specify a function's parameter or return types: they must be inferable from the context in which it is being used.
Examples:
["fn", "a", "b", ["+", ["var", "a"], ["var", "b"]]]
["replace", ["get", "name"], "(\w+),\s*(\w+)",
["fn", "g1", "g2", [ "concat", ["var", "g1"], " ", ["upcase", ["var", "g2"]] ] ]
]
A function is applied with ["apply", fn_expression, a_expr, b_expr, (etc.)], where a_expr, b_expr, etc. are the arguments to the fn_expression.
Example:
["let", "sum", ["fn", "a", "b", ["+", ["var", "a"], ["var", "b"]]],
["apply", ["var", "sum"], 1, 2]
]
function_body_expression is lexically scoped: it can reference any let vars that are in scope at the site of the "fn" definition. Recursion is not allowed: if the "fn" definition itself is being bound to a variable, that variable is not in scope within function_body_expression.
Subtyping: if a function of type (T) -> U is expected, then a function (X) -> Y is valid as long as T is a subtype of X and Y is a subtype of U. E.g.: if (string, value) -> value is expected, then (string, string) -> number is valid.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue names no implementation files or tests; begin by locating the expression-language parser, type checker, evaluator, and existing let/var handling. Review the linked discussions and determine how function definition, application, lexical scope, type inference, subtyping, and recursion rules should be specified. Done means the design is agreed and the expression language supports the stated use cases with coverage for the proposed semantics.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend, web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100