Named bindings, flatMap, sortBy, entries, sort/reverse, template upgrades, and pipe RFC#27
Merged
Merged
Conversation
…ate upgrades
Implements the post-v1.1.0 roadmap items from the Mobius Ops
integration feedback.
Language surface:
- Every iterating form (map, filter, flatMap, any, all, find, count,
sortBy) now accepts a three-arg shape that names the element
binding: filter(orders, o, o.status == "paid"). The named form
binds only the chosen name plus index, leaving `it` resolving to an
enclosing two-arg form, which closes the nested-forms scoping gap.
Two-arg calls are unchanged.
- New flatMap form: like map, but list body results splice
element-by-element, nil splices as nothing, and any other value
appends as a single element.
- New sortBy form: stable sort of a copy by a per-element key
expression; keys must be all numbers or all strings.
- New entries(m) builtin in the default set: sorted key-value pairs
of a string-keyed map, making maps iterable through the forms.
- New sort(xs) and reverse(xs) builtins in CollectionFuncs().
Templates:
- Composite values (maps, slices, arrays, structs) render as compact
JSON with HTML escaping disabled instead of Go map syntax. This is
a rendering behavior change; see the spec's templates section.
- WithTemplateDelimiters("${{", "}}") replaces the default `${`/`}`
so shell snippets like ${HOME} pass through literally.
- WithTemplateFormatter(fn) is an escape hatch that runs before the
default rendering chain.
- Template errors now report 1-based line:column with the byte
offset as supplementary detail.
- New Template.Segments() exposes literal and expression segments
with positions and each segment's compiled *Program, for editor
hints and per-segment Identifiers().
- Template-only options passed to Compile fail with ErrCompile
instead of being silently ignored.
Also adds docs/rfcs/0001-pipe-operator.md, a design RFC for
repurposing `|` as a pipeline operator. No implementation commitment;
the recommendation is opt-in via a WithPipeOperator option if
adopted.
Spec, guides, examples, llms.txt, README, doc tests, and runnable
example companions are updated to match. Template fuzzing now covers
custom delimiters.
Co-Authored-By: Claude Fable 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the post-v1.1.0 roadmap distilled from the Mobius Ops integration feedback. (v1.1.0 itself was tagged from main separately, with the lazy-
ifbehavior change called out in its release notes.)Named element bindings in higher-order forms
Every iterating form (
map,filter,flatMap,any,all,find,count,sortBy) now accepts a three-arg shape that names the element binding:The named form binds only the chosen name plus
index. It does not bindit, so an enclosing two-arg form'sitstays reachable from inside the body, which closes the documented nested-forms scoping gap. Two-arg calls are unchanged, and a three-arg call previously failed the arity check at eval time, so no working program changes behavior.it,index,true,false,nil,map, andifare rejected as binding names with clear errors.Identifiers(), the did-you-mean suggester, and the streamedfilter(xs, p)[n]fast path all honor the new form.New forms and builtins
flatMap(xs, body)/flatMap(xs, x, body): likemap, but list body results splice element-by-element,nilsplices as nothing (mirroring the nil-is-empty-list rule), and any other value appends as a single element. Strings never split into runes; splicing is one level deep.sortBy(xs, key)/sortBy(xs, x, key): stable sort of a copy by a per-element key expression. Keys must be all numbers (int/int compares as int64, mixed promotes to float64, same as<) or all strings; anything else is anErrEvaluatenaming the offending element.entries(m): new default builtin next tokeys; sorted[{"key": k, "value": v}, ...], making maps iterable through the forms.sort(xs)/reverse(xs): new opt-in builtins inCollectionFuncs(). Both return copies;sortreorders original elements without converting them.Template batch
&<>survive in webhook payloads and prompts):${config}now produces{"retries":3,"timeout":"30s"}instead ofmap[retries:3 timeout:30s]. Composites that marshal to a JSON string (e.g.time.Time) render unquoted. Unmarshalable values fall back to the old formatting. This is a rendering behavior change, called out in the spec and guides.WithTemplateDelimiters("${{", "}}"): GHA-style delimiters so shell/JS text likeecho ${HOME}passes through literally. Opener must end in a{run with the matching}closer;$$escaping applies only to$-prefixed openers.WithTemplateFormatter(fn): per-template rendering escape hatch; returning false falls through to the default chain.line:column(offset kept as supplementary detail), for both parse-time and render-time failures.Template.Segments()returns[]TemplateSegment{Literal, Source, Offset, Line, Column, Program}, so hosts get editor hints, highlighting, and per-segmentIdentifiers()without re-implementing the template scanner (the Mobiusparse.gouse case).Compilenow fail withErrCompileinstead of being silently ignored.NewTemplateresolves options once and reuses the config across segments.Pipe operator RFC (no implementation)
docs/rfcs/0001-pipe-operator.mdcovers the proposeda | f(x)→f(a, x)desugar: precedence rules with worked examples, optional-access interaction, error taxonomy, the Go-subset identity question argued both ways, and alternatives. Recommendation: if adopted, ship opt-in behindWithPipeOperator(). No commitment made.Docs and tests
Spec,
higher-order-patterns.md(including a rewrite of the "why there's nolet" section),templates.md,examples.md,llms.txt, README, doc-sync tests, and runnable example companions are all updated. New test files cover named bindings (scoping, shadowing, fast path, errors),flatMap/sortBy,entries/sort/reverse, and the template features; template fuzzing gained a custom-delimiter target (all five fuzz targets run clean).🤖 Generated with Claude Code