
编程语言编译器语言运行时开发工具【免费下载链接】unisonA friendly programming language from the future项目地址https://gitcode.com/gh_mirrors/un/unison点击查看免费下载本文基于 Unison 开源仓库中的 UCM 交互转录测试文件 bug-strange-closure.md深入剖析 Unison 可计算文档computable documentation在控制台渲染docFormatConsolePretty.get下的完整工作方式以及一个反编译问题与 GHC 非确定性崩溃 strange closure error 的复现路径。读完本文你将掌握 Doc2 文档模型的全部核心元素、display与手动渲染的差异以及如何在转录测试中定位此类运行时崩溃。转录文件背景这是一份幂等idempotentUCM 转录测试Unison 仓库用 UCMUnison Codebase Manager转录文件transcripts作为可执行的交互式测试用例文件中的ucm代码块会被 UCM 逐条执行输出被记录为.output.md对照文件。位于unison-src/transcripts/idempotent/目录下的转录是幂等的即反复运行应得到完全一致的输出用于守护代码库操作add、undo等与渲染行为的稳定性。bug-strange-closure.md 就是其中之一它专门复现并记录了两类问题对一份名为doc.guide的文档执行display时存在反编译decompilation问题——文档本身无法通过默认路径被正确展示通过rendered Pretty.get (docFormatConsole doc.guide)手工渲染后可以正常展示但直接求值rendered会以非确定性non-deterministic的方式触发 GHC 的 strange closure error 崩溃。转录开头通过两行 UCM 命令建立运行环境 builtins.mergeio lib.builtins load unison-src/transcripts-using-base/doc.md.files/syntax.ubuiltins.mergeio把内置的 IO 相关定义合并进lib.builtins命名空间为后续渲染所需的Pretty、ConsoleText等库提供依赖load则把含doc.guide等文档定义的文件加载进 scratch 区。doc.guideUnison 可计算文档的能力全景doc.guide是一份刻意编写的文档的文档几乎覆盖了 Doc2 文档模型的每一种元素。它在转录中的首次display输出就是全文的渲染结果也是理解整个问题的最小上下文 display doc.guide # Unison computable documentation # Basic formatting Paragraphs are separated by one or more blanklines. Sections have a title and 0 or more paragraphs or other section elements. Text can be bold, *italicized*, ~~strikethrough~~, or monospaced (or monospaced). You can link to Unison terms, types, and external URLs: * An external url * Some is a term link; Optional is a type link * A named type link and a named term link. Term links are handy for linking to other documents! You can use {{ .. }} to escape out to regular Unison syntax, for instance __not bold__. This is useful for creating documents programmatically or just including other documents. *Next up:* lists # Lists # Bulleted lists Bulleted lists can use , -, or * for the bullets (though the choice will be normalized away by the pretty-printer). They can be nested, to any depth: * A * B * C * C1 * C2 # Numbered lists 1. A 2. B 3. C The first number of the list determines the starting number in the rendered output. The other numbers are ignored: 10. A 11. B 12. C Numbered lists can be nested as well, and combined with bulleted lists: 1. Wake up. * What am I doing here? * In this nested list. 2. Take shower. 3. Get dressed. # Evaluation Expressions can be evaluated inline, for instance 2. Blocks of code can be evaluated as well, for instance: id x x id (sqr 10) ⧨ 100 also: match 1 with 1 - hi _ - goodbye ⧨ hi To include a typechecked snippet of code without evaluating it, you can do: use Nat * cube : Nat - Nat cube x x * x * x # Including Unison source code Unison definitions can be included in docs. For instance: structural type Optional a None | Some a sqr : Nat - Nat sqr x use Nat * x * x Some rendering targets also support folded source: structural type Optional a None | Some a sqr : Nat - Nat sqr x use Nat * x * x You can also include just a signature, inline, with sqr : Nat - Nat, or you can include one or more signatures as a block: sqr : Nat - Nat Nat. : Nat - Nat - Nat Or alternately: List.map : (a -{e} b) - [a] -{e} [b] # Inline snippets You can include typechecked code snippets inline, for instance: * f x Nat. sqr 1 - the 2 says to ignore the first two arguments when rendering. In richer renderers, the sqr link will be clickable. * If your snippet expression is just a single function application, you can put it in double backticks, like so: sqr x. This is equivalent to sqr x. # Non-Unison code blocks Use three or more single quotes to start a block with no syntax highlighting: raw _____ _ | | |___|_|___ ___ ___ | | | | |_ -| . | | |_____|_|_|_|___|___|_|_| You can use three or more backticks plus a language name for blocks with syntax highlighting: Haskell -- A fenced code block which isnt parsed by Unison reverse foldl (flip (:)) [] Scala // A fenced code block which isnt parsed by Unison def reverseA xs.foldLeft(Nil : List[A])((acc,a) a : acc) There are also asides, callouts, tables, tooltips, and more. These dont currently have special syntax; just use the {{ }} syntax to call these functions directly. docAside : Doc2 - Doc2 docCallout : Optional Doc2 - Doc2 - Doc2 docBlockquote : Doc2 - Doc2 docTooltip : Doc2 - Doc2 - Doc2 docTable : [[Doc2]] - Doc2 This is an aside. ( Some extra detail that doesnt belong in main text. ) | This is an important callout, with no icon. | | | This is an important callout, with an icon. The text | wraps onto multiple lines. And what is the use of a book, thought Alice, without pictures or conversation? *Lewis Carroll, Alices Adventures in Wonderland* Hover over me a b A longer paragraph that will split onto multiple lines, such that this row occupies multiple lines in the rendered table. Some text More text Zounds!这段输出集中体现了 Doc2 文档模型的若干关键语义段落与节段落由空行分隔节由标题加若干段落组成行内样式**bold**、*italicized*、~~strikethrough~~、monospaced均受支持链接既可以链接外部 URL也可以链接 Unison 术语term与类型type命名链接named link在更丰富的渲染器中可点击跳转{{ .. }}转义用{{ .. }}逃逸回普通 Unison 语法可用于程序化生成文档或内嵌其他文档列表项目符号列表的/-/*会被 pretty-printer 归一化编号列表的起始号由第一个数字决定其余数字被忽略列表可任意嵌套、可与符号列表混用求值支持Eval整段代码求值并显示⧨结果与EvalInline行内求值如2两种方式源码展示支持包含类型定义/函数定义Source、可折叠源码FoldedSource、行内签名SignatureInline与签名块Signature、行内示例Example其数字参数表示渲染时忽略前 N 个参数如f x Nat. sqr 1的2非 Unison 代码块三个及以上单引号开头的块不做语法高亮raw三个及以上反引号加语言名则带高亮如 Haskell、Scala且内容不会被 Unison 解析高级元素docAside、docCallout、docBlockquote、docTooltip、docTable等目前没有专用语法统一通过{{ }}调用对应函数实现。反编译问题为什么display doc.guide不可靠转录在第一次display doc.guide之后紧跟一行重要注解We can display the guide before and after adding it to the codebase...随后 add将doc.guide加入代码库But we cant display this due to a decompilation problem.也就是说尽管转录中两次display doc.guide加入代码库前后都打印出了上面那份完整渲染文本但这份转录本身就是为了记录一个已知缺陷而写的display的默认路径对这份文档存在反编译decompilation问题——文档的某些特殊形式SpecialForm无法通过常规的反编译渲染管线还原成可读文本因此不能依赖display来可靠展示复杂文档。这解释了为什么转录随后绕开了display改用在 Unison 层手工调用渲染函数的方式rendered Pretty.get (docFormatConsole doc.guide)UCM 对这段 scratch 代码的类型检查结果是Loading changes detected in scratch.u. rendered : Annotated () (Either SpecialForm ConsoleText) Run update to apply these changes to your codebase.rendered的类型是Annotated () (Either SpecialForm ConsoleText)——这正是Pretty文档的底层表示一棵带()注解用于布局、缩进等的节点树每个叶子要么是Left SpecialForm不可打印的特殊形式要么是Right ConsoleText可直接输出的终端文本。docFormatConsole的作用就是把Doc2翻译成这棵树。源码级透视docFormatConsole 与 ConsoleTextdocFormatConsole不是魔法它在当前仓库中有完整的 Unison 源码实现位于 IOSource.hs。该文件第 391 行把它注册为运行时可直接调用的内置引用doc2FormatConsoleRef termNamed syntax.docFormatConsole其签名IOSource.hs 第 923 行与核心结构如下syntax.docFormatConsole : Doc2 - Pretty (Either SpecialForm ConsoleText)实现中定义了一个内部go函数对Doc2的每个构造子逐一映射为Pretty文档IOSource.hs 第 930-979 行Word t→ 直接输出文本tCode d→ 包裹在中CodeBlock typ d→ 输出 类型名 换行 内容 Italic、Strikethrough→ 分别以*、~~包裹对Paragraph结构做了首尾分组处理Doc2.Bold d→ 用ConsoleText.Bold映射整段内容Style、Anchor→ 透传Blockquote→ 每行前缀Pretty.indentBlankline→\n\nLinebreak→\nTooltip→ 只渲染内部内容当前控制台渲染器丢弃提示文本Aside→ 以()包裹并用BrightBlack前景色弱化Callout None d→ 前缀|Callout (Some icon) d→ 用ConsoleText.Bold渲染图标行、空行再渲染正文Table rows→ 交给Pretty.tableFolded→ 拼接摘要与详情Paragraph ds→Pretty.wrap自动折行BulletedList ds→ 每项* 缩进Pretty.sepBy换行分隔NumberedList n ds→ 用Nat.toText、Text.alignRightWith计算并右对齐编号宽度实现1.、10.的等宽对齐。与docFormatConsole配套的ConsoleText与ANSI.Color类型也在同文件定义IOSource.hs 第 883-894 行ConsoleText由Plain、Foreground、Background、Bold、Underline、Invert构造ANSI.Color提供 16 种终端颜色。这解释了上面display rendered输出中Right (ConsoleText.Bold (Plain Unison))这类叶子的来源——rendered求值结果正是docFormatConsole生成的整棵Annotated树终端渲染层再把它解释成带样式的彩色文本。手工渲染可以工作display rendered转录随后执行 display rendered输出与display doc.guide完全一致全文与上面那份渲染文本相同证明经docFormatConsolePretty.get手工渲染的文档内容是正确的绕开了反编译问题。之后再次 add把rendered加入代码库再次 display rendered输出不变再执行 undo撤销这次添加 undo Here are the changes I undid Added definitions: 1. rendered : Annotated () (Either SpecialForm ConsoleText)GHC strange closure error非确定性崩溃的复现问题出在最后一步。转录用 rendered直接求值这个巨大的Annotated结构而不是用display渲染它rendered Pretty.get (docFormatConsole doc.guide) rendered这一次UCM 返回的是一棵未经渲染的原始数据结构而不是排版后的文本。转录中记录了这条命令的开头部分Loading changes detected in scratch.u. rendered : Annotated () (Either SpecialForm ConsoleText) Run update to apply these changes to your codebase. 3 | rendered ⧩ Annotated.Group () (Annotated.Append () [ Indent () (Lit () (Right (Plain # ))) (Lit () (Right (Plain ))) (Annotated.Group () (Wrap () (Annotated.Append () [ Lit () (Right (ConsoleText.Bold (Plain Unison))) , ...可以看到doc.guide的每个字词都被拆成了独立的Lit () (Right (Plain …))叶子并以Annotated.Group/Annotated.Append/Indent/Wrap层层嵌套——这份文档的渲染树规模相当庞大转录原文仅这一个求值输出就占据了数千行。转录对此问题的定性非常明确And then this sometimes generates a GHC crash strange closure error but doesnt seem deterministic.也就是说直接求值这个巨大的闭包结构时GHC 有时会抛出 strange closure error 并崩溃而且该崩溃不是确定性的——同样的输入不同运行可能崩溃、也可能不崩溃。从仓库现状看该问题没有任何修复记录或对应源码补丁本转录文件就是当前仓库中唯一记录该崩溃的测试用例。从其幂等目录属性可以推断该转录在 CI 中需要输出稳定一致而这类非确定性崩溃正是幂等转录测试要盯防的对象凡是结果无法稳定复现的求值路径都会被转录系统标记出来防止回归时被静默吞掉。结合 IOSource.hs 的实现可以理解崩溃为何难以避免docFormatConsole会对整棵Doc2递归生成Pretty文档而Pretty.get是纯求值无任何惰性截断一旦把生成的巨型Annotated树整体求值并打印会在运行时栈/堆上构造大量相互嵌套的闭包Lit、Wrap、Indent、Append、Group层层包裹此时遇到 GHC 在闭包标记或 GC 路径上的已知缺陷就会以 strange closure error 形式崩溃。这也是为何转录演示的正确姿势是用display rendered走终端渲染管线渲染层按需消费Pretty文档而不是用 rendered把整棵树裸打印出来。如何查看与复现完整转录与全部交互输出见 bug-strange-closure.md渲染函数源码与ConsoleText/ANSI.Color类型定义见 unison-runtime/src/Unison/Runtime/IOSource.hsdocFormatConsole自第 923 行起同主题的其他文档转录可横向对照 Doc2 的不同渲染目标如 doc2.md、doc-formatting.md、doc2markdown.mdMarkdown 渲染与 api-doc-rendering.mdDoc2 的语法级定义与解析测试可参考 unison-syntax/test/Unison/Test/Doc.hs。本地复现路径克隆仓库后进入unison-cli组件运行转录测试scripts/test.sh或cabal驱动的转录套件会执行unison-src/transcripts/idempotent/下的用例对照.output.md检查输出。值得注意的是由于该崩溃非确定性反复运行bug-strange-closure.md用例即可观察到偶发的 GHC strange closure error这正是该转录存在的意义把一个难以稳定复现的运行时缺陷固化成可重复触发的测试供后续修复时验证。小结bug-strange-closure.md用一份近乎文档功能全集的doc.guide同时验证了三件事Unison 可计算文档Doc2在控制台端的完整表达能力docFormatConsole把Doc2翻译成Pretty (Either SpecialForm ConsoleText)的底层机制以及display反编译缺陷与 GHC 非确定性 strange closure error 这两个已知问题的复现方式。对 Unison 运行时、文档系统或转录测试框架感兴趣的同学这是一份少有的、同时覆盖功能正确性与崩溃复现两面的第一手素材。赞分享编程语言编译器语言运行时开发工具【免费下载链接】unisonA friendly programming language from the future项目地址https://gitcode.com/gh_mirrors/un/unison点击查看免费下载相关推荐Unison 可计算文档Computable Documents完整指南Doc2 语法与 UCM 实战Unison 可计算文档Computable Documents完整指南Doc2 语法与 UCM 实战 Unison 的文档不是普通的 Markdown编程语言编译器语言运行时开发工具Unison 可计算文档Computable Documents完全指南从 {{ }} 语法到实时求值的文档系统Unison 可计算文档Computable Documents完全指南从 {{ }} 语法到实时求值的文档系统 Unison 的文档不是独立于代码的静态编程语言编译器语言运行时开发工具Unison 文档导出实战用 docs.to-html 将命名空间内全部 Doc2 文档批量渲染为 HTML 站点Unison 文档导出实战用 docs.to html 将命名空间内全部 Doc2 文档批量渲染为 HTML 站点 导读 在 Unison 语言中文档 D编程语言编译器语言运行时开发工具上一篇Budibase 内嵌 Apache CouchDB Helm Chart 部署与配置全指南集群安装、密钥管理、升级迁移与参数详解下一篇Pydantic 严格模式Strict Mode完全指南从字段级到全局的严格校验配置与源码剖析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考