diff options
| -rw-r--r-- | 2025/10/30/二〇二五年十月三十日/index.html | 4 | ||||
| -rw-r--r-- | search.xml | 30 |
2 files changed, 17 insertions, 17 deletions
diff --git a/2025/10/30/二〇二五年十月三十日/index.html b/2025/10/30/二〇二五年十月三十日/index.html index 09825f2b..93573c37 100644 --- a/2025/10/30/二〇二五年十月三十日/index.html +++ b/2025/10/30/二〇二五年十月三十日/index.html @@ -190,8 +190,8 @@ <p>从那以后,我偶尔还会闻到那种味道。公交车拐弯的时候,风从窗缝里钻进来,地铁门打开的时候,站台上一阵匆忙的脚步后,忽然静下来的那一刻。我不知道它为什么会出现,也不刻意寻找。它像朋友一样,来了就坐一会儿,走了也不会留下地址。</p> <p>然后我遇见了你。</p> <p>起初我们并肩走在一条街上,街灯刚亮,影子从脚边拖到墙根。你说话的时候,声音不急也不慢。我听见了你的过去,但不是像在听故事那样去比较谁更动人,我只是听着你。你给我看了你的手心,那上面有被太阳晒过后的浅色纹理,也有你习惯把指甲剪得很短的认真。我心里有一种安静,它不是从谁那里借来的,而是像从很远的地方自己走来的。</p> -<p>我知道你不是他,他是一种很亮的影子,只能在黑暗里存在。而你会在这里,在光亮里也在风里,在你的沉默里也在你的笑声里。时间不会让你跟他合在一起,时间只会让你在我旁边,成为一个可以站着的人,一个愿意陪我走过同一条街、同一种气味、同一种阳光的人。</p> -<p>于是我想给你那朵黄玫瑰的记忆。不是因为我想要你变成他的样子,而是因为我在你身上看见了自己喜欢的那种安静和从容。我想让你在今后的某一天,当公交门打开,站台忽然安静下来,当你走在一条熟悉的路上,风从树梢里穿过,当你坐在窗边,光从书页上滑过去的时候,能闻到那种味道,能想起那一刻的我们,我们在傍晚的风里站着,既不躲藏也不假装,我们把时间握在手里,像握着一朵温柔得让人不需要理由的花。</p> +<p>我知道你不是她,她是一种很亮的影子,只能在黑暗里存在。而你会在这里,在光亮里也在风里,在你的沉默里也在你的笑声里。时间不会让你跟她合在一起,时间只会让你在我旁边,成为一个可以站着的人,一个愿意陪我走过同一条街、同一种气味、同一种阳光的人。</p> +<p>于是我想给你那朵黄玫瑰的记忆。不是因为我想要你变成她的样子,而是因为我在你身上看见了自己喜欢的那种安静和从容。我想让你在今后的某一天,当公交门打开,站台忽然安静下来,当你走在一条熟悉的路上,风从树梢里穿过,当你坐在窗边,光从书页上滑过去的时候,能闻到那种味道,能想起那一刻的我们,我们在傍晚的风里站着,既不躲藏也不假装,我们把时间握在手里,像握着一朵温柔得让人不需要理由的花。</p> <p>如果你愿意,我可以每天傍晚经过花店门口,我们可以把那种味道带回家,用一只透明的瓶子装起来,不需要解释它来自哪里,也不需要把它和任何过去比较。它只会在你需要的时候出现,像一个老朋友,提醒你,不是每一次都要变成别人,不是每一次都需要证明你已经忘记。你可以是现在的你,我可以是现在的我。我们可以在同一个黄昏里站一会儿,看看天空从浅到深,看看风从我们旁边走过,看看影子在我们的脚边拉长。</p> <p>黄玫瑰的味道不会要求我们变成谁,它只会给我们一点轻的力气,让我们在时间里往前走走。我把这份力气给你,也给我自己,然后我们就接着往前走,带着这种不喧哗的光。</p> @@ -3793,8 +3793,8 @@ NestJS 依赖其底层 HTTP 适配器(默认为 Express)来解析传入的� <p>从那以后,我偶尔还会闻到那种味道。公交车拐弯的时候,风从窗缝里钻进来,地铁门打开的时候,站台上一阵匆忙的脚步后,忽然静下来的那一刻。我不知道它为什么会出现,也不刻意寻找。它像朋友一样,来了就坐一会儿,走了也不会留下地址。</p> <p>然后我遇见了你。</p> <p>起初我们并肩走在一条街上,街灯刚亮,影子从脚边拖到墙根。你说话的时候,声音不急也不慢。我听见了你的过去,但不是像在听故事那样去比较谁更动人,我只是听着你。你给我看了你的手心,那上面有被太阳晒过后的浅色纹理,也有你习惯把指甲剪得很短的认真。我心里有一种安静,它不是从谁那里借来的,而是像从很远的地方自己走来的。</p> -<p>我知道你不是他,他是一种很亮的影子,只能在黑暗里存在。而你会在这里,在光亮里也在风里,在你的沉默里也在你的笑声里。时间不会让你跟他合在一起,时间只会让你在我旁边,成为一个可以站着的人,一个愿意陪我走过同一条街、同一种气味、同一种阳光的人。</p> -<p>于是我想给你那朵黄玫瑰的记忆。不是因为我想要你变成他的样子,而是因为我在你身上看见了自己喜欢的那种安静和从容。我想让你在今后的某一天,当公交门打开,站台忽然安静下来,当你走在一条熟悉的路上,风从树梢里穿过,当你坐在窗边,光从书页上滑过去的时候,能闻到那种味道,能想起那一刻的我们,我们在傍晚的风里站着,既不躲藏也不假装,我们把时间握在手里,像握着一朵温柔得让人不需要理由的花。</p> +<p>我知道你不是她,她是一种很亮的影子,只能在黑暗里存在。而你会在这里,在光亮里也在风里,在你的沉默里也在你的笑声里。时间不会让你跟她合在一起,时间只会让你在我旁边,成为一个可以站着的人,一个愿意陪我走过同一条街、同一种气味、同一种阳光的人。</p> +<p>于是我想给你那朵黄玫瑰的记忆。不是因为我想要你变成她的样子,而是因为我在你身上看见了自己喜欢的那种安静和从容。我想让你在今后的某一天,当公交门打开,站台忽然安静下来,当你走在一条熟悉的路上,风从树梢里穿过,当你坐在窗边,光从书页上滑过去的时候,能闻到那种味道,能想起那一刻的我们,我们在傍晚的风里站着,既不躲藏也不假装,我们把时间握在手里,像握着一朵温柔得让人不需要理由的花。</p> <p>如果你愿意,我可以每天傍晚经过花店门口,我们可以把那种味道带回家,用一只透明的瓶子装起来,不需要解释它来自哪里,也不需要把它和任何过去比较。它只会在你需要的时候出现,像一个老朋友,提醒你,不是每一次都要变成别人,不是每一次都需要证明你已经忘记。你可以是现在的你,我可以是现在的我。我们可以在同一个黄昏里站一会儿,看看天空从浅到深,看看风从我们旁边走过,看看影子在我们的脚边拉长。</p> <p>黄玫瑰的味道不会要求我们变成谁,它只会给我们一点轻的力气,让我们在时间里往前走走。我把这份力气给你,也给我自己,然后我们就接着往前走,带着这种不喧哗的光。</p> ]]></content> @@ -6126,6 +6126,19 @@ NestJS 依赖其底层 HTTP 适配器(默认为 Express)来解析传入的� </tags> </entry> <entry> + <title>隐藏一些OCaml Effect的机制,让其语法在精神上更接近delimcc</title> + <url>/2023/06/28/%E9%9A%90%E8%97%8F%E4%B8%80%E4%BA%9BOCaml-Effect%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%E8%AE%A9%E5%85%B6%E8%AF%AD%E6%B3%95%E5%9C%A8%E7%B2%BE%E7%A5%9E%E4%B8%8A%E6%9B%B4%E6%8E%A5%E8%BF%91delimcc/</url> + <content><![CDATA[<p><a href="https://github.com/kayceesrk/delimcc_of_fxhandler">delimcc_of_fxhandler这个库</a>在OCaml5的effect handlers上实现了一些delimcc原语(shift/reset, control/prompt这些):</p> +<figure class="highlight ocaml"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> p = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"><span class="keyword">assert</span> (<span class="literal">[]</span> = push_prompt p (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="number">1</span>::<span class="number">2</span>::take_subcont p (<span class="keyword">fun</span> _k -> <span class="literal">[]</span>)));</span><br><span class="line"><span class="keyword">assert</span> ([<span class="number">1</span>;<span class="number">2</span>] = push_prompt p (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="number">1</span>::<span class="number">2</span>::take_subcont p (<span class="keyword">fun</span> k -> push_subcont k <span class="literal">[]</span>)));</span><br><span class="line"><span class="keyword">assert</span> (<span class="number">135</span> =</span><br><span class="line"> <span class="keyword">let</span> p1 = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">let</span> p2 = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">let</span> p3 = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">let</span> pushtwice sk =</span><br><span class="line"> sk (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> sk (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> shift0 p2 (<span class="keyword">fun</span> sk2 -> sk2 (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> sk2 (<span class="keyword">fun</span> <span class="literal">()</span> -> <span class="number">3</span>))) <span class="literal">()</span>))</span><br><span class="line"> <span class="keyword">in</span></span><br><span class="line"> push_prompt p1 (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> push_prompt p2 (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> push_prompt p3 (<span class="keyword">fun</span> <span class="literal">()</span> -> shift0 p1 pushtwice <span class="literal">()</span>) + <span class="number">10</span>) + <span class="number">1</span>) + <span class="number">100</span>);</span><br><span class="line"></span><br><span class="line">print_endline <span class="string">"Success!"</span></span><br></pre></td></tr></table></figure> +<p>另外, <a href="https://github.com/avsm/ocaml/commits/effect-syntax">avsm这里</a>可以看到一些OCaml的Effect Syntax进展。</p> +<p>还有 <a href="https://github.com/dhil/ocaml-multicont">multi-shot continuations in OCaml</a>,在这个仓库里面还讨论了一些有趣的问题,例如,OCaml 编译器和runtime会做出一些假设从而进行一些优化,这些优化在使用multi-shot continutation时是不可取的(或完全错误的)。编译器优化导致错误的一个例子是堆到栈的转换,例如:</p> +<figure class="highlight ocaml"><table><tr><td class="code"><pre><span class="line"><span class="comment">(* An illustration of how the heap to stack optimisation is broken.</span></span><br><span class="line"><span class="comment"> * This example is adapted from de Vilhena and Pottier (2021).</span></span><br><span class="line"><span class="comment"> * file: heap2stack.ml</span></span><br><span class="line"><span class="comment"> * compile: ocamlopt -I $(opam var lib)/multicont multicont.cmxa heap2stack.ml</span></span><br><span class="line"><span class="comment"> * run: ./a.out *)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">(* We first require a little bit of setup. The following declares an</span></span><br><span class="line"><span class="comment"> operation `Twice' which we use to implement multiple returns. *)</span></span><br><span class="line"><span class="keyword">type</span> _ <span class="type">Effect</span>.t += <span class="type">Twice</span> : <span class="built_in">unit</span> <span class="type">Effect</span>.t</span><br><span class="line"></span><br><span class="line"><span class="comment">(* The handler `htwice' interprets `Twice' by simply invoking its</span></span><br><span class="line"><span class="comment"> continuation twice. *)</span></span><br><span class="line"><span class="keyword">let</span> htwice : (<span class="built_in">unit</span>, <span class="built_in">unit</span>) <span class="type">Effect</span>.<span class="type">Deep</span>.handler</span><br><span class="line"> = { retc = (<span class="keyword">fun</span> x -> x)</span><br><span class="line"> ; exnc = (<span class="keyword">fun</span> e -> raise e)</span><br><span class="line"> ; effc = (<span class="keyword">fun</span> (<span class="keyword">type</span> a) (eff : a <span class="type">Effect</span>.t) -></span><br><span class="line"> <span class="keyword">let</span> <span class="keyword">open</span> <span class="type">Effect</span>.<span class="type">Deep</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">match</span> eff <span class="keyword">with</span></span><br><span class="line"> | <span class="type">Twice</span> -> <span class="type">Some</span> (<span class="keyword">fun</span> (k : (a, _) continuation) -></span><br><span class="line"> continue (<span class="type">Multicont</span>.<span class="type">Deep</span>.clone_continuation k) <span class="literal">()</span>;</span><br><span class="line"> continue k <span class="literal">()</span>)</span><br><span class="line"> | _ -> <span class="type">None</span>) }</span><br><span class="line"></span><br><span class="line"><span class="comment">(* Now for the interesting stuff. In the code below, the compiler will</span></span><br><span class="line"><span class="comment"> perform an escape analysis on the reference `i' and deduce that it</span></span><br><span class="line"><span class="comment"> does not escape the local scope, because it is unaware of the</span></span><br><span class="line"><span class="comment"> semantics of `perform Twice', hence the optimiser will transform</span></span><br><span class="line"><span class="comment"> `i' into an immediate on the stack to save a heap allocation. As a</span></span><br><span class="line"><span class="comment"> consequence, the assertion `(!i = 1)' will succeed twice, whereas</span></span><br><span class="line"><span class="comment"> it should fail after the second return of `perform Twice'. *)</span></span><br><span class="line"><span class="keyword">let</span> heap2stack <span class="literal">()</span> =</span><br><span class="line"> <span class="type">Effect</span>.<span class="type">Deep</span>.match_with</span><br><span class="line"> (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="keyword">let</span> i = <span class="built_in">ref</span> <span class="number">0</span> <span class="keyword">in</span></span><br><span class="line"> <span class="type">Effect</span>.perform <span class="type">Twice</span>;</span><br><span class="line"> i := !i + <span class="number">1</span>;</span><br><span class="line"> <span class="type">Printf</span>.printf <span class="string">"i = %d\n%!"</span> !i;</span><br><span class="line"> <span class="keyword">assert</span> (!i = <span class="number">1</span>))</span><br><span class="line"> <span class="literal">()</span> htwice</span><br><span class="line"></span><br><span class="line"><span class="comment">(* The following does not trigger an assertion failure. *)</span></span><br><span class="line"><span class="keyword">let</span> _ = heap2stack <span class="literal">()</span></span><br><span class="line"></span><br><span class="line"><span class="comment">(* To fix this issue, we can wrap reference allocations in an instance</span></span><br><span class="line"><span class="comment"> of `Sys.opaque_identity'. However, this is not really a viable fix</span></span><br><span class="line"><span class="comment"> in general, as we may not have access to the client code that</span></span><br><span class="line"><span class="comment"> allocates the reference! *)</span></span><br><span class="line"><span class="keyword">let</span> heap2stack' <span class="literal">()</span> =</span><br><span class="line"> <span class="type">Effect</span>.<span class="type">Deep</span>.match_with</span><br><span class="line"> (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="keyword">let</span> i = <span class="type">Sys</span>.opaque_identity (<span class="built_in">ref</span> <span class="number">0</span>) <span class="keyword">in</span></span><br><span class="line"> <span class="type">Effect</span>.perform <span class="type">Twice</span>;</span><br><span class="line"> i := !i + <span class="number">1</span>;</span><br><span class="line"> <span class="type">Printf</span>.printf <span class="string">"i = %d\n%!"</span> !i;</span><br><span class="line"> <span class="keyword">assert</span> (!i = <span class="number">1</span>))</span><br><span class="line"> <span class="literal">()</span> htwice</span><br><span class="line"></span><br><span class="line"><span class="comment">(* The following triggers an assertion failure. *)</span></span><br><span class="line"><span class="keyword">let</span> _ = heap2stack' <span class="literal">()</span></span><br></pre></td></tr></table></figure> +]]></content> + <tags> + <tag>Technique</tag> + </tags> + </entry> + <entry> <title>金匮要略</title> <url>/2023/03/04/%E9%87%91%E5%8C%AE%E8%A6%81%E7%95%A5/</url> <content><![CDATA[<p>臟腑經絡先後病脈證第一問曰:上工治未病,何也?師曰:夫治未病者,見肝之病,知肝傳脾,當先實脾,四季脾王不受邪,即勿補之;中工不曉相傳,見肝之病,不解實脾,惟治肝也。</p> @@ -7393,19 +7406,6 @@ NestJS 依赖其底层 HTTP 适配器(默认为 Express)来解析传入的� </tags> </entry> <entry> - <title>隐藏一些OCaml Effect的机制,让其语法在精神上更接近delimcc</title> - <url>/2023/06/28/%E9%9A%90%E8%97%8F%E4%B8%80%E4%BA%9BOCaml-Effect%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%E8%AE%A9%E5%85%B6%E8%AF%AD%E6%B3%95%E5%9C%A8%E7%B2%BE%E7%A5%9E%E4%B8%8A%E6%9B%B4%E6%8E%A5%E8%BF%91delimcc/</url> - <content><![CDATA[<p><a href="https://github.com/kayceesrk/delimcc_of_fxhandler">delimcc_of_fxhandler这个库</a>在OCaml5的effect handlers上实现了一些delimcc原语(shift/reset, control/prompt这些):</p> -<figure class="highlight ocaml"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> p = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"><span class="keyword">assert</span> (<span class="literal">[]</span> = push_prompt p (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="number">1</span>::<span class="number">2</span>::take_subcont p (<span class="keyword">fun</span> _k -> <span class="literal">[]</span>)));</span><br><span class="line"><span class="keyword">assert</span> ([<span class="number">1</span>;<span class="number">2</span>] = push_prompt p (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="number">1</span>::<span class="number">2</span>::take_subcont p (<span class="keyword">fun</span> k -> push_subcont k <span class="literal">[]</span>)));</span><br><span class="line"><span class="keyword">assert</span> (<span class="number">135</span> =</span><br><span class="line"> <span class="keyword">let</span> p1 = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">let</span> p2 = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">let</span> p3 = new_prompt <span class="literal">()</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">let</span> pushtwice sk =</span><br><span class="line"> sk (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> sk (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> shift0 p2 (<span class="keyword">fun</span> sk2 -> sk2 (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> sk2 (<span class="keyword">fun</span> <span class="literal">()</span> -> <span class="number">3</span>))) <span class="literal">()</span>))</span><br><span class="line"> <span class="keyword">in</span></span><br><span class="line"> push_prompt p1 (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> push_prompt p2 (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> push_prompt p3 (<span class="keyword">fun</span> <span class="literal">()</span> -> shift0 p1 pushtwice <span class="literal">()</span>) + <span class="number">10</span>) + <span class="number">1</span>) + <span class="number">100</span>);</span><br><span class="line"></span><br><span class="line">print_endline <span class="string">"Success!"</span></span><br></pre></td></tr></table></figure> -<p>另外, <a href="https://github.com/avsm/ocaml/commits/effect-syntax">avsm这里</a>可以看到一些OCaml的Effect Syntax进展。</p> -<p>还有 <a href="https://github.com/dhil/ocaml-multicont">multi-shot continuations in OCaml</a>,在这个仓库里面还讨论了一些有趣的问题,例如,OCaml 编译器和runtime会做出一些假设从而进行一些优化,这些优化在使用multi-shot continutation时是不可取的(或完全错误的)。编译器优化导致错误的一个例子是堆到栈的转换,例如:</p> -<figure class="highlight ocaml"><table><tr><td class="code"><pre><span class="line"><span class="comment">(* An illustration of how the heap to stack optimisation is broken.</span></span><br><span class="line"><span class="comment"> * This example is adapted from de Vilhena and Pottier (2021).</span></span><br><span class="line"><span class="comment"> * file: heap2stack.ml</span></span><br><span class="line"><span class="comment"> * compile: ocamlopt -I $(opam var lib)/multicont multicont.cmxa heap2stack.ml</span></span><br><span class="line"><span class="comment"> * run: ./a.out *)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">(* We first require a little bit of setup. The following declares an</span></span><br><span class="line"><span class="comment"> operation `Twice' which we use to implement multiple returns. *)</span></span><br><span class="line"><span class="keyword">type</span> _ <span class="type">Effect</span>.t += <span class="type">Twice</span> : <span class="built_in">unit</span> <span class="type">Effect</span>.t</span><br><span class="line"></span><br><span class="line"><span class="comment">(* The handler `htwice' interprets `Twice' by simply invoking its</span></span><br><span class="line"><span class="comment"> continuation twice. *)</span></span><br><span class="line"><span class="keyword">let</span> htwice : (<span class="built_in">unit</span>, <span class="built_in">unit</span>) <span class="type">Effect</span>.<span class="type">Deep</span>.handler</span><br><span class="line"> = { retc = (<span class="keyword">fun</span> x -> x)</span><br><span class="line"> ; exnc = (<span class="keyword">fun</span> e -> raise e)</span><br><span class="line"> ; effc = (<span class="keyword">fun</span> (<span class="keyword">type</span> a) (eff : a <span class="type">Effect</span>.t) -></span><br><span class="line"> <span class="keyword">let</span> <span class="keyword">open</span> <span class="type">Effect</span>.<span class="type">Deep</span> <span class="keyword">in</span></span><br><span class="line"> <span class="keyword">match</span> eff <span class="keyword">with</span></span><br><span class="line"> | <span class="type">Twice</span> -> <span class="type">Some</span> (<span class="keyword">fun</span> (k : (a, _) continuation) -></span><br><span class="line"> continue (<span class="type">Multicont</span>.<span class="type">Deep</span>.clone_continuation k) <span class="literal">()</span>;</span><br><span class="line"> continue k <span class="literal">()</span>)</span><br><span class="line"> | _ -> <span class="type">None</span>) }</span><br><span class="line"></span><br><span class="line"><span class="comment">(* Now for the interesting stuff. In the code below, the compiler will</span></span><br><span class="line"><span class="comment"> perform an escape analysis on the reference `i' and deduce that it</span></span><br><span class="line"><span class="comment"> does not escape the local scope, because it is unaware of the</span></span><br><span class="line"><span class="comment"> semantics of `perform Twice', hence the optimiser will transform</span></span><br><span class="line"><span class="comment"> `i' into an immediate on the stack to save a heap allocation. As a</span></span><br><span class="line"><span class="comment"> consequence, the assertion `(!i = 1)' will succeed twice, whereas</span></span><br><span class="line"><span class="comment"> it should fail after the second return of `perform Twice'. *)</span></span><br><span class="line"><span class="keyword">let</span> heap2stack <span class="literal">()</span> =</span><br><span class="line"> <span class="type">Effect</span>.<span class="type">Deep</span>.match_with</span><br><span class="line"> (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="keyword">let</span> i = <span class="built_in">ref</span> <span class="number">0</span> <span class="keyword">in</span></span><br><span class="line"> <span class="type">Effect</span>.perform <span class="type">Twice</span>;</span><br><span class="line"> i := !i + <span class="number">1</span>;</span><br><span class="line"> <span class="type">Printf</span>.printf <span class="string">"i = %d\n%!"</span> !i;</span><br><span class="line"> <span class="keyword">assert</span> (!i = <span class="number">1</span>))</span><br><span class="line"> <span class="literal">()</span> htwice</span><br><span class="line"></span><br><span class="line"><span class="comment">(* The following does not trigger an assertion failure. *)</span></span><br><span class="line"><span class="keyword">let</span> _ = heap2stack <span class="literal">()</span></span><br><span class="line"></span><br><span class="line"><span class="comment">(* To fix this issue, we can wrap reference allocations in an instance</span></span><br><span class="line"><span class="comment"> of `Sys.opaque_identity'. However, this is not really a viable fix</span></span><br><span class="line"><span class="comment"> in general, as we may not have access to the client code that</span></span><br><span class="line"><span class="comment"> allocates the reference! *)</span></span><br><span class="line"><span class="keyword">let</span> heap2stack' <span class="literal">()</span> =</span><br><span class="line"> <span class="type">Effect</span>.<span class="type">Deep</span>.match_with</span><br><span class="line"> (<span class="keyword">fun</span> <span class="literal">()</span> -></span><br><span class="line"> <span class="keyword">let</span> i = <span class="type">Sys</span>.opaque_identity (<span class="built_in">ref</span> <span class="number">0</span>) <span class="keyword">in</span></span><br><span class="line"> <span class="type">Effect</span>.perform <span class="type">Twice</span>;</span><br><span class="line"> i := !i + <span class="number">1</span>;</span><br><span class="line"> <span class="type">Printf</span>.printf <span class="string">"i = %d\n%!"</span> !i;</span><br><span class="line"> <span class="keyword">assert</span> (!i = <span class="number">1</span>))</span><br><span class="line"> <span class="literal">()</span> htwice</span><br><span class="line"></span><br><span class="line"><span class="comment">(* The following triggers an assertion failure. *)</span></span><br><span class="line"><span class="keyword">let</span> _ = heap2stack' <span class="literal">()</span></span><br></pre></td></tr></table></figure> -]]></content> - <tags> - <tag>Technique</tag> - </tags> - </entry> - <entry> <title>领域驱动设计中的“聚合根”</title> <url>/2025/03/13/%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1%E4%B8%AD%E7%9A%84%E2%80%9C%E8%81%9A%E5%90%88%E6%A0%B9%E2%80%9D/</url> <content><