mapbox / mapbox/mapbox-gl-js

Add support for first-class functions in expressions

Open
#7,010 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

api :memo: cross-platform :tv: feature :green_apple:
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:

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.