尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Roc 语言关联类型在容器中的限定引用:List、Try 与记录字段的源码级解析

Roc 语言关联类型在容器中的限定引用:List、Try 与记录字段的源码级解析 Roc 语言关联类型在容器中的限定引用List、Try 与记录字段的源码级解析【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc本文以 Roc 编译器仓库中的快照测试 nominal_associated_lookup_in_containers.md 为核心完整讲解限定类型Qualified types出现在类型应用List、Try 等容器类型中这一语言特性包括关联块associated block的语法、Foo.Bar形式的点分限定类型如何作为泛型参数使用、以及它如何在词法、语法、规范化与类型推断各编译阶段被处理。读完本文你将掌握在 Roc 中编写类型模块 容器组合代码的方法并理解如何通过仓库内的快照测试验证与复现这一编译行为。一、背景什么是快照测试为什么用它讲类型特性本仓库Roc 语言编译器通过快照测试来固化编译器各阶段的行为。快照测试的机制说明见 test/snapshots/README.md每个快照文件捕获一段 Roc 源码经过词法分析tokenization、解析parsing、规范化canonicalization、类型检查等编译阶段的输出用于在编译器行为发生意外变化时检测回归。本文核心文档即一个典型的typefile快照其META区明确写道descriptionQualified types in type applications (List, Try, etc.)PROBLEMS区为NIL说明该源码通过了全部编译检查、不产生任何诊断报告是验证限定类型可用于容器类型实参这一能力的正例快照。二、核心源码逐行拆解关联类型如何进入容器快照的SOURCE区即typefile:Foo.roc指向的文件内容是本文的灵魂原文完整如下Foo : [Whatever].{ Bar : [A, B, C] Error : [Oops, Yikes] } items : List(Foo.Bar) items [A, B, C] result : Try(Foo.Bar, Foo.Error) result Ok(A) nested : { bar : Foo.Bar, count : U64 } nested { bar: A, count: 1 }2.1 关联块associated block语法第一段代码声明了一个名为Foo的类型模块type moduleFoo : [Whatever].{ Bar : [A, B, C] Error : [Oops, Yikes] }Foo : [Whatever]Foo本身是一个标签联合类型tag union含一个标签Whatever后面的. { ... }是关联块块内可以继续声明类型与值它们属于Foo的关联条目associated items块内声明了Bar : [A, B, C]标签联合三个标签和Error : [Oops, Yikes]标签联合两个标签。于是Foo.Bar与Foo.Error成为两个限定类型qualified type这是点分名称查找的核心对象。仓库中test/snapshots/nominal/目录下还有大量同类正例例如 nominal_associated_lookup_type.md 展示了更简单的单层关联Foo : [Whatever].{ Bar : [Something] } myBar : Foo.Bar myBar Something2.2 用例一List(Foo.Bar) —— 容器类型参数items : List(Foo.Bar) items [A, B, C]类型标注List(Foo.Bar)表示元素类型为Foo.Bar的列表值构造[A, B, C]使用不带限定符的标签A/B/C——由于类型已由标注确定编译器能通过类型上下文把A解析为Foo.Bar.A从CANONICALIZE区可以看到编译后该声明的类型被规范化表示为(ty-apply (name List) (builtin) (ty-lookup (name Foo.Bar) (local)))List被标记为 builtin内置类型构造器Foo.Bar被标记为 local本地名义类型查找。这印证了内置容器 本地限定类型的组合在规范化阶段就已被正确区分并解析。2.3 用例二Try(Foo.Bar, Foo.Error) —— 多参数类型应用result : Try(Foo.Bar, Foo.Error) result Ok(A)Try是 Roc 内置的结果类型携带两个类型参数成功值类型与错误类型这里成功类型用Foo.Bar、错误类型用Foo.Error两个不同关联类型同时进入同一个类型应用值构造Ok(A)中的A同样依赖类型标注消歧为Foo.Bar.ACANONICALIZE区对应输出为(ty-apply (name Try) (builtin) (ty-lookup (name Foo.Bar) (local)) (ty-lookup (name Foo.Error) (local)))两个实参都是 local 名义类型查找。2.4 用例三记录类型字段中的限定类型nested : { bar : Foo.Bar, count : U64 } nested { bar: A, count: 1 }记录类型{ bar : Foo.Bar, count : U64 }的字段bar使用了限定类型Foo.Bar字段count使用内置类型U64值构造{ bar: A, count: 1 }混合了由上下文消歧的标签A与整数字面量1CANONICALIZE区显示count字段解析为(ty-lookup (name U64) (builtin))bar字段为(ty-lookup (name Foo.Bar) (local))。这三个用例共同覆盖了限定类型在容器类型List、多参泛型类型Try、记录字段三种常见类型应用/复合位置中的引用这正是该快照描述Qualified types in type applications (List, Try, etc.)的全部含义。三、编译管线逐阶段输出解析快照的价值在于把同一份源码在编译器各阶段的中间表示都钉住。下面按阶段解读本文快照的输出。3.1 TOKENS词法层面UpperIdent,OpColonEqual,OpenSquare,UpperIdent,CloseSquare,Dot,OpenCurly, UpperIdent,OpColonEqual,OpenSquare,UpperIdent,Comma,UpperIdent,Comma,UpperIdent,CloseSquare, UpperIdent,OpColonEqual,OpenSquare,UpperIdent,Comma,UpperIdent,CloseSquare, CloseCurly, LowerIdent,OpColon,UpperIdent,NoSpaceOpenRound,UpperIdent,NoSpaceDotUpperIdent,CloseRound, ...关键观察Foo :被词法化为UpperIdentOpColonEqual:是类型声明运算符关联块边界由OpenSquare[、CloseSquare]、Dot.、OpenCurly/CloseCurly组成List(Foo.Bar)被词法化为UpperIdentNoSpaceOpenRoundUpperIdentNoSpaceDotUpperIdentCloseRound注意Foo.Bar整体是一个tokenNoSpaceDotUpperIdent无空格点连接大写标识符说明限定类型名在词法阶段就被识别为单一记号而不是两个独立标识符items [A, B, C]中A/B/C是普通UpperIdent是OpAssign。3.2 PARSE语法树形态(file (type-mod) (statements (s-type-decl (header (name Foo) (args)) (ty-tag-union (tags (ty (name Whatever)))) (associated (s-type-decl (header (name Bar) (args)) (ty-tag-union (tags (ty (name A)) (ty (name B)) (ty (name C))))) (s-type-decl (header (name Error) (args)) (ty-tag-union (tags (ty (name Oops)) (ty (name Yikes))))))) (s-type-anno (name items) (ty-apply (ty (name List)) (ty (name Foo.Bar)))) ...要点顶层被解析为(type-mod)类型模块Foo的类型声明带有associated子节点内部是Bar、Error两个s-type-decl关联块是语法树上的一级结构items : List(Foo.Bar)是s-type-annoty-apply节点List与Foo.Bar分别是ty-apply的两个参数——限定类型在语法树上就是一个整体类型节点Ok(A)被解析为e-applyOk应用于A记录字面量被解析为e-record。3.3 FORMATTED格式化回读一致FORMATTED区与SOURCE完全一致仅缩进统一为制表符。这说明该快照同时固化了格式化器的行为关联块内缩进一层、类型标注与声明之间空行、{ bar: A, count: 1 }冒号后空格的规范样式均可从该区逐字核对。3.4 CANONICALIZE规范化后的核心证据(can-ir (d-let (p-assign (ident items)) (e-list (elems (e-tag (name A)) (e-tag (name B)) (e-tag (name C)))) (annotation (ty-apply (name List) (builtin) (ty-lookup (name Foo.Bar) (local))))) ... (s-nominal-decl (ty-header (name Foo)) (ty-tag-union (ty-tag-name (name Whatever)))) (s-nominal-decl (ty-header (name Foo.Bar)) (ty-tag-union (ty-tag-name (name A)) (ty-tag-name (name B)) (ty-tag-name (name C)))) (s-nominal-decl (ty-header (name Foo.Error)) (ty-tag-union (ty-tag-name (name Oops)) (ty-tag-name (name Yikes)))))规范化阶段揭示了两件重要事实限定类型的符号被拆平Foo、Foo.Bar、Foo.Error变成三个独立的s-nominal-decl名义类型声明。关联块中的嵌套类型在符号层面被提升为全局名义类型这正是nominal命名语义的体现参见 Glossary.md 中 Nominal Typing 词条类型引用被标注来源ty-lookup (name Foo.Bar) (local)表示本地名义类型查找ty-lookup (name U64) (builtin)表示内置类型查找ty-apply (name List) (builtin)表示内置类型构造器。类型系统据此区分用户定义的本地类型与语言内置类型。从源码结构看关联块的解析与规范化逻辑位于 src/canonicalize/ 目录其中CIR.zig、Can.zig、Scope.zig等均涉及 associated 相关处理负责把语法层面的associated子树转换为上述s-nominal-decl序列。3.5 TYPES类型推断结果(inferred-types (defs (patt (type List(Foo.Bar))) (patt (type Try(Foo.Bar, Foo.Error))) (patt (type { bar: Foo.Bar, count: U64 }))) (type_decls (nominal (type Foo) (ty-header (name Foo))) (nominal (type Foo.Bar) (ty-header (name Foo.Bar))) (nominal (type Foo.Error) (ty-header (name Foo.Error)))) (expressions ...))最终三个定义的类型分别为List(Foo.Bar)、Try(Foo.Bar, Foo.Error)、{ bar: Foo.Bar, count: U64 }与手写标注完全吻合类型声明区列出三个名义类型。这也说明限定类型与容器组合后类型信息在推断结果中完整保留、没有被扁平化或丢失。类型渲染把Foo.Bar打印为限定名的底层逻辑可进一步参考 src/types/TypeWriter.zig 中startNominalType等函数。四、关联类型的更多实战形态同一主题的扩展证据限定类型 容器/复合类型并非孤立场景仓库test/snapshots/nominal/目录下同一主题的快照给出了更丰富的用法可作为本特性的延伸学习材料关联类型 函数类型nominal_associated_lookup_mixed.md 展示了在关联块内定义值和函数并在顶层用Foo.transform(Foo.defaultBar)限定调用Foo : [Whatever].{ Bar : [A, B, C] defaultBar Bar.A transform : Foo.Bar - Foo.Bar transform |x| x } result2 : Foo.Bar result2 result result : Foo.Bar result Foo.transform(Foo.defaultBar)注意这里transform的类型标注Foo.Bar - Foo.Bar说明限定类型同样可以作为函数类型参数且值调用采用Foo.transform的限定名形式。深层嵌套关联nominal_associated_lookup_nested.md 展示了关联块套关联块以及限定值引用Foo.Bar.bazFoo : [Whatever].{ Bar : [Something].{ baz 5 } } myType : Foo.Bar myType Something myNum : U64 myNum Foo.Bar.baz这验证了点分限定链Foo.Bar.baz可以穿透多层关联块且在 CANONICALIZE 阶段Foo.Bar.baz被解析为独立的d-let绑定(p-assign (ident Foo.Bar.baz)) (e-num (value 5))值引用myNum Foo.Bar.baz则变成e-lookup-local。简单限定类型标注nominal_associated_lookup_type.md 给出最朴素的类型标注引用关联类型的基线用例。这些快照共同说明Foo.Bar形式的限定类型在标注、容器实参、函数类型、值调用、深层嵌套等位置均可一致工作属于 Roc 类型模块体系中的通用机制。五、动手验证在仓库中运行该快照快照测试作为编译器开发流程的一部分可通过仓库的 snapshot tool 运行见 test/snapshots/README.md。前提是环境已具备 Zig 工具链并完成构建参见 BUILDING_FROM_SOURCE.md。运行全部快照zig build run-snapshot-tool只更新/运行单个快照即本文核心文档zig build run-snapshot-tool -- test/snapshots/nominal/nominal_associated_lookup_in_containers.md当编译器行为有预期变更、需要刷新期望值时zig build run-snapshot-tool -- test/snapshots/nominal/nominal_associated_lookup_in_containers.md --update-expected需要说明的约束快照测试是只读校验其意义在于固化输出、检测回归——本文核心文档的EXPECTED与PROBLEMS均为NIL意味着这段限定类型入容器的代码在当前编译器上可以零诊断通过。若你修改了编译器实现导致该快照输出变化CI 与本地快照工具都会提示差异这正是这类测试对语言特性演进的价值所在。六、小结以 nominal_associated_lookup_in_containers.md 为核心本文完整还原了 Roc 语言限定类型进入容器类型这一特性的全貌语法上Foo : [Whatever].{ ... }的关联块可以声明Bar、Error等嵌套类型形成Foo.Bar限定类型使用上限定类型可以作为List(Foo.Bar)、Try(Foo.Bar, Foo.Error)等类型应用的实参也可以出现在记录字段{ bar : Foo.Bar }中构造值时标签可依赖类型标注自动消歧编译上词法阶段Foo.Bar是单一 token语法阶段是完整类型节点规范化阶段被拆平为三个s-nominal-decl并通过ty-lookup (local/builtin)标注来源类型推断阶段则原样保留List(Foo.Bar)等复合类型验证上通过zig build run-snapshot-tool可以随时复现与回归校验这一行为。围绕该特性test/snapshots/nominal/目录下的关联快照函数类型、嵌套关联、限定调用等与 src/canonicalize/、src/types/TypeWriter.zig 的源码共同构成一条完整的学习路径适合希望深入理解 Roc 类型模块体系与编译器流水线的开发者继续挖掘。【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表