smallnest / smallnest/seq

记录:Zip/Zip3/Zip4 为何暂不可由自由函数改为方法(跟踪上游 golang/go#80172)

Open
#44 1 comment 0 reactions 1 assignee View on GitHub

@smallnest is already working on this.

Since Jun 28, 2026.

docs priority: low
Dominant language
Go
Stars
66
Forks
1
PR merge metrics
No merged PRs in 30d

Description

背景

ZipZip3Zip4 当前是自由函数(multiseq.go),而非 Seq[T] 上的方法。本文档记录其为何不能直接改成 func (s Seq[L]) Zip[R](b Seq[R]) Seq[Pair[L,R]] 这样的方法形式 —— 便于日后 Go 泛型限制演进时回看。

现状

期望的方法签名:

func (s Seq[L]) Zip[R any](b Seq[R]) Seq[Pair[L, R]]

go1.27rc1 上编译失败:

seq.go:39:10: instantiation cycle:
    T instantiated as Pair[T, R]

Zip3/Zip4 同理(T instantiated as Tuple3[…] / Tuple4[…])。已在本地实测确认(go1.27rc1 darwin/arm64)。

为什么不可改

核心原因:方法返回类型把接收者自身的定义泛型类型Seq 用一个派生自接收者类型参数 T、但又不嵌套 Seq 自身的实参 Pair[T,R] 重新实例化,触发了 Go 编译器的单态化(monomorphization)循环熔断。

机制(与上游 golang/go#80109 的论证一致):Go 对每个具体实例化生成全部方法。若允许 Seq[int] 的方法返回 Seq[Pair[int,R]],编译器就要为 Seq[Pair[int,R]] 生成全部方法,其签名又含更深的实例化……无穷展开、编译永不终止。instantiation cycle: T instantiated as Pair[T, R] 是熔断器。

这与三条 Go 限制的关系(容易混淆,逐一区分)

限制 形态 状态 与本 issue 关系
golang/go#75883(Go 1.26 放开) 约束自引用 type T[P T[P]] 已放开 无关SeqT 约束是 any,没碰约束自引用。不要误以为「1.26 放开自引用了 Zip 就能用方法」。
golang/go#80109(已关闭) 自嵌套返回 A[A[T]] / Seq[Seq[T]] working as intended 同源机制的另一子类。Chunk/WindowSeq[Seq[T]] 属此,已被 Griesemer 判 intended,预期不放开。
golang/go#80172(OPEN) 派生非自嵌套返回 A[[]T] / Seq[Pair[T,R]] 未定论,无 Go 团队裁决 正是本 issue 所述情形

关于 golang/go#80172

上游 issue golang/go#80172 —— cmd/compile, go/types: generic method returning receiver type instantiated with derived receiver type parameter reports instantiation cycle(2026-06-26 提,作者 JasonMing,截至本文 OPEN,无 Go 团队回复)—— 精准描述了本 issue 的情形。其最小复现:

type A[T any] struct{}
func (a A[T]) M() A[[]T]  { panic("TODO") }   // Bad — instantiation cycle
func F[T any](a A[T]) A[[]T] { panic("TODO") } // OK — 同形状的自由函数可编译

A[[]T] 与本库的 Seq[Pair[L,R]] 同构:都是「把接收者类型用派生自 T、但不嵌套接收者自身的实参重新实例化」。作者的论点很关键 —— []T(以及本库的 Pair[T,R]并不递归展开 A/Seq,因此 #80109 那套「自嵌套无穷展开」的论证套不上这一子类;且等价的自由函数能编译,说明返回类型本身有限且静态可知。作者请求 Go 团队「要么让它编译,要么文档化为何不行」—— 目前无裁决

也就是说:本 issue 描述的限制当前确实生效,但它是否「按设计如此」尚未被 Go 团队定论(与 #80109 自嵌套类不同)。

当前 workaround(已采用)

不改成方法,保持自由函数形式。返回类型用另一个定义类型 Seq2[L,R](或底层 iter.Seq[Pair[L,R]])即可绕开 —— 实测可编译且惰性可链:

// 已验证可编译 + 惰性可链(非终止):
func (s Seq[L]) ZipM[R any](b Seq[R]) Seq2[L, R]   // 返回 Seq2,而非 Seq[Pair[L,R]]

ZipWith(返回 Seq[C]C 为全新参数)与 UnzipSeq2 上的方法,返回 Seq[K]/Seq[V])均可为方法,本库取自由函数纯为多源对称。

验收 / 跟踪

  • 现状已记录:Zip/Zip3/Zip4 为自由函数,go1.27rc1 实测方法形式报 instantiation cycle
  • 机制与上游 issue 的对应关系已厘清(#75883 / #80109 / #80172)
  • 跟踪 golang/go#80172:若 Go 团队裁定该子类「应放开」并修复,则本库可将 Zip/Zip3/Zip4 改为方法(返回 Seq[Pair[L,R]] / Seq[Tuple3[…]] / Seq[Tuple4[…]]),并更新 multiseq.go 注释、docs/API.md 3.3 表、docs/en.html/zh.html 的 multi-section desc
  • 若 Go 团队裁定该子类 intended(同 #80109),则本 issue 关闭、现状定型

Type

docs / tracking · 优先级 low · 阻塞于上游 golang/go#80172

相关

  • 代码:multiseq.go 文件头注释、docs/API.md §3.3、docs/en.html/zh.html multi-section
  • 上游:golang/go#80172(本情形)、golang/go#80109(自嵌套同源)、golang/go#75883(约束自引用,无关)
  • 本库同源现象:Chunk/Window 返回 iter.Seq[Seq[T]](属 #80109 自嵌套类)

Contributor guide

No contributing guide indexed for this repository

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.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.