<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss"
        xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
        xmlns:media="http://search.yahoo.com/mrss/"><channel>
<title>TojoQK の投稿</title>
<atom:link href="https://www.tojo.tokyo/rss.xml" rel="self" type="application/rss+xml" />
<link>https://www.tojo.tokyo</link>
<description><![CDATA[]]></description>
<language>ja</language>
<pubDate>Tue, 26 May 2026 15:36:18 +0000</pubDate>
<lastBuildDate>Tue, 26 May 2026 15:36:18 +0000</lastBuildDate>
<generator>Emacs 30.2 Org-mode 9.7.11</generator>
<webMaster>masaya@tojo.tokyo (Masaya Tojo)</webMaster>
<image>
<url>https://www.tojo.tokyo/static/image/QK.png</url>
<title>TojoQK の投稿</title>
<link>https://www.tojo.tokyo</link>
</image>

<item>
<title>Agdaのコードを含む記事を書いて公開できるようになりました</title>
<link>https://www.tojo.tokyo/posts/agda-on-www-tojo-tokyo.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/agda-on-www-tojo-tokyo.html</guid>
<pubDate>Wed, 27 May 2026 00:30:00 +0000</pubDate>
<category><![CDATA[Web]]></category>
<category><![CDATA[Agda]]></category>
<description><![CDATA[<div class="org-src-container">
<pre class="src src-agda2">module agda-on-www-tojo-tokyo where
</pre>
</div>
<div id="outline-container-org3690cf9" class="outline-3">
<h3 id="org3690cf9">はじめに</h3>
<div class="outline-text-3" id="text-org3690cf9">
<p>
ついに Agda のコードを含む記事を書いて公開できるようになりました！
サイト上ではほとんど音沙汰なしな状態でしたが、実は1年ほど前から積極的に Agda を触っており、
今となっては趣味で使うプログラミング言語はほとんど Agda になっています。
</p>

<p>
インフラも整ったところなので、
これからは好きなように Agda の記事を書いていきたいと考えてます。
</p>
</div>
</div>
<div id="outline-container-orgf07ebd7" class="outline-3">
<h3 id="orgf07ebd7">「TojoQK の投稿」について</h3>
<div class="outline-text-3" id="text-orgf07ebd7">
<p>
この「TojoQK の投稿」というサイトは最初の投稿からもう6年も経過しており、
途中で静的サイトジェネレータを切り替えて最終的に Emacs Lisp を駆使して、
そこそこ楽にサイトデプロイできるような独自スクリプトで無理矢理成立させているという現実があります。
</p>

<p>
このようにかなり強引なビルドシステムによってかろうじて成立しているサイトなので、
これに Agda による文芸的プログラミング機能をうまく組み合わせてデプロイするのは大変でした。
こういった事情により、このサイトは長い間放置されてきたわけです。
</p>

<p>
技術的負債が解決したということは全くないのですが、
なんとか Agda のビルドを挟んでうまく、サイトに反映できるようになったというところです。
</p>
</div>
</div>
<div id="outline-container-orge43fc27" class="outline-3">
<h3 id="orge43fc27">Agda の lagda 機能について</h3>
<div class="outline-text-3" id="text-orge43fc27">
<p>
このサイトは全て Org mode で書かれているのですが、
なんと Agda は拡張子を <code>.lagda.org</code> とすることで、 Org-mode 中にかかれた Agda コードを問題なくコンパイルできます。
しかも、 <code>polymode</code> とうまく組み合わせることで Org-mode を使いながら、Agda の型チェックもできるという夢のような状態も作れます。
</p>

<p>
たとえば、 1 + 1 = 2 をここで Agda にチェックさせてみましょう。
</p>

<div class="org-src-container">
<pre class="src src-agda2">  module _ where
    open import Data.Nat using (ℕ; _+_)
    open import Relation.Binary.PropositionalEquality using (_≡_; refl)

    1+1≡2 : 1 + 1 ≡ 2
    1+1≡2 = refl
</pre>
</div>

<p>
無事に 1 + 1 ≡ 2 であることを証明できている。すごい！
ここで <code>refl</code> だけ色が違っているように見えると思うものですが、
この色の違いの理由は <code>refl</code> がコンストラクタであることを意味しています。
Agdaはコンスラクタかどうかについて構文的に区別することができないので、
それがコンストラクタかどうかはAgdaコンパイラだけが知っています。
このAgdaコンパイラによる色付けがセマンティックハイライティングです。
Agda のコンパイルが通らない限り、この色付けは決してできないのです。
</p>
</div>
</div>
<div id="outline-container-orge7121af" class="outline-3">
<h3 id="orge7121af">2026年に個人でブログサイトを自作する意義</h3>
<div class="outline-text-3" id="text-orge7121af">
<p>
私は静的サイトビルドのワークフローで自作のビルドプロセスを通した後に、
Emacs の <code>org-publish</code> で <code>org-html-export-to-html</code> でエクスポートしています。
</p>

<p>
この自作ビルドプロセスがもともとあったおかげで、
<code>agda -html --html-highlight=code</code> のようなコマンドを用いて Agda の記事の公開に成功しています。
</p>

<p>
おそらく、既成のビルドツールのプロセスに <code>agda --html</code> で生成したファイルで置換するみたいな処理を挟むのは、
相当に面倒くさいと思うので、こればっかりは色々自力でやっていてよかったなあと感じています。
</p>

<p>
こういった圧倒的な自由度こそが、個人サイトの醍醐味だというものです。
</p>
</div>
</div>
<div id="outline-container-org23baec5" class="outline-3">
<h3 id="org23baec5">Agda、Agda-stdlibのソースファイルを部分的にホスティングする問題</h3>
<div class="outline-text-3" id="text-org23baec5">
<p>
<code>agda --html</code> で <code>.lagda.org</code> のファイルをビルドすると、
Agdaコード中にリンクが自動的に張られクリックすると定義を見にいけるというとても便利な機能があるのですが、
自分の書いたコードだけでなく Agda や Agda-stdlib のコードへのリンクが張られてしまう問題があります。
</p>

<p>
リンクが張られる以上は一緒にホスティングしないといけないという問題があるので、ここは結構どうするか考えさせられました。
おそらく、Agda チームの方々はこのあたりの法的問題についてあんまり真剣に考えていないのではないかという疑惑を正直持っているのですが、
少なくともMITライセンス文言に従うためには私のサイト上でライセンス表示をする必要がありそうです。
</p>

<p>
そのため、Agda の記事の場合は「※本記事はAgdaコードを含んでいます。Agdaコード中のリンク先ファイルのライセンスについては<a href="https://www.tojo.tokyo/agda-license/">Agda関連ライセンスについて</a>を参照してください」という文言とリンクを張ることで解決しました。
このページには Agda と Agda-stdlib のバージョン番号を乗せていて、ビルドサーバーの Agda のバージョンと食い違ったら CI がコケるようにしています。
なので、バージョンが新しくなるたびにライセンス表記を手動で更新する運用でとりあえずいこうと考えています。
</p>

<p>
また、検索エンジンの検索結果に私のサイトに載った Agda のソースコードが一覧されてしまうと悪いので、
Agda, Agda-stdlib のファイルのページについては robots の指定で <code>noindex</code> を付けています。
</p>
</div>
</div>
<div id="outline-container-org32c5428" class="outline-3">
<h3 id="org32c5428">おわりに</h3>
<div class="outline-text-3" id="text-org32c5428">
<p>
ともかく、Agda のコードがかけるようになってよかったです。
私の趣味のプログラミングはほぼ全て Agda になっているような状況なので、
Agda の記事が書けないのは致命的な問題でした。
</p>

<p>
この記事では <code>1 + 1 = 2</code> としかいっていないですが、
今後は色々思いついたことを記事にしていこうかと思っています。
</p>
</div>
</div>
]]></description>
</item>
<item>
<title>命名の本質</title>
<link>https://www.tojo.tokyo/posts/naming.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/naming.html</guid>
<pubDate>Sun, 25 May 2025 00:52:00 +0000</pubDate>

<description><![CDATA[<div id="outline-container-naming-what" class="outline-3">
<h3 id="naming-what">命名とは何か</h3>
<div class="outline-text-3" id="text-naming-what">
<p>
命名とは世界を形作る行為である。
これは過言ではなく、仏教的真理から導かれる帰結である。
</p>

<p>
命名を軽視するものは世界のあり方を根本から誤認しており、
それは命名の前に「本質」が既にあるという誤認に基づいている。
世界に「本質」などなく「名」そのものが我々に「本質」を感じさせているに過ぎない。
</p>
</div>
</div>
<div id="outline-container-naming-ontology" class="outline-3">
<h3 id="naming-ontology">命名と存在論</h3>
<div class="outline-text-3" id="text-naming-ontology">
<p>
仏教では「諸行無常」と「諸法無我」を真理としていて、
この二つを体得することで「涅槃寂静」すなわち楽になれるという、
考え(これを三法印という)で構成されている。
</p>

<p>
仏教的真理について中観派的な観点から説明する。
ただし、本節の内容は自己の解釈を含み中観派の主張を正確に再現できていない可能性があることについて注意していただきたい。
「諸行無常」とはこの世のすべてのものは常にうつろい変わっていくということを意味している。
このとき、それぞれが独立で変化するのではなく互いに依存しあって変化していると考える。
故に、固定的な「実体」は何一つとして存在していない、すなわち「諸法無我」であると導くのである。
しかし、我々は世界に「実体」があるかのように誤認する。
その原因は「名」にある。我々は言語によって世界を分別する。
現象やものに「名」がつくことによりそれが固定的な実体があるかのように誤解するのである。
それは、世界に実体が存在しその実体が生起したり消滅したりするという世界の誤認へと導いているのだ。
</p>

<p>
ここで、命名の実相が見えてくる。
命名とは世界の諸行無常の真のあり方を覆い尽くし、
この世界に固定的な構造や関係を構築する行為なのである。
</p>
</div>
</div>
<div id="outline-container-naming-programming" class="outline-3">
<h3 id="naming-programming">プログラミングにおける命名</h3>
<div class="outline-text-3" id="text-naming-programming">
<p>
プログラミングでは、関数、変数、型、クラス、ファイルととにかく命名の機会が多い。
しかしそれは必然である。
プログラミングとは命名によって計算機上の世界を構築する行為だからだ。
</p>

<p>
そもそも計算機はバイナリ列を操作する装置にすぎない。
そこに名を与えなければどのような操作も意味を持たない。
バイナリ列への恣意的な意味づけがなければ、
ただバイナリの状態が変化しているだけである。
このありようはまさしく諸行無常であり計算機世界は離散的に空である。
</p>

<p>
しかし、我々は計算機で意味ある計算を行っている。
それは名付けによって意味のある世界を計算機上で構築した結果である。
</p>

<p>
システム設計者はこのことを強く認識する必要がある。
なぜなら不適切な命名をすればシステムを正しく理解・構築することはできなくなる。
システムが名と名との関係によって構成されている以上、これは自明である。
</p>

<p>
命名とは設計そのものである。
</p>
</div>
</div>
]]></description>
</item>
<item>
<title>Typed RacketでLuhnアルゴリズムを実装した</title>
<link>https://www.tojo.tokyo/posts/typed-racket-luhn.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/typed-racket-luhn.html</guid>
<pubDate>Sun, 12 Jan 2025 00:30:00 +0000</pubDate>
<category><![CDATA[Racket]]></category>
<description><![CDATA[<div id="outline-container-2025-01-12-hajimeni" class="outline-3">
<h3 id="2025-01-12-hajimeni">はじめに</h3>
<div class="outline-text-3" id="text-2025-01-12-hajimeni">
<p>
最近、クレジットカード番号まわりを扱う開発をする機会があり、
クレジットカード番号の入力ミスを検知するのに使用されている Luhn アルゴリズムについて知りました。
</p>

<p>
これは面白い仕組みだなと思い、
趣味プログラミングの一環として Typed Racket で実装してみました。
</p>

<p>
その結果、いい感じに実装できたので記事に残します。
Luhn アルゴリズムについての詳細には触れず、
Typed Racket で実装したときの感想や、
最終的な実装に至るまでに考えたことなどについて主に書きます。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-luhn-towa" class="outline-3">
<h3 id="2025-01-12-luhn-towa">Luhn アルゴリズムとは</h3>
<div class="outline-text-3" id="text-2025-01-12-luhn-towa">
<p>
<a href="https://ja.m.wikipedia.org/wiki/Luhn%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0">Luhn アルゴリズム</a>は、<a href="https://en.m.wikipedia.org/wiki/Hans_Peter_Luhn">Hans Peter Luhn</a> 氏が発明したチェックサム方式の誤りを検知する方法です。
</p>

<p>
番号の右端に誤り検出用の番号(チェックディジット)を一つ追加しておき、
決められた方法で計算した値が10で割り切れるかどうかで判定します。
10で割り切れる場合は誤り未検出で、
割きれない場合は誤りを検出できます。
誤りが検出されない場合に、元の誤りがないことを証明できているわけではないことに注意が必要です。
(0と9の入れ替えなどの簡単な入力間違えであってもすり抜けるケースがあります)
</p>

<p>
手元に番号が書かれたカードや紙があるときに、
コンピュータに手入力する場合には入力ミスがよく起きるものですが、入力ミスのたびに番号を管理しているシステムまで問い合わせまでしてしまうと無駄が多いです。
番号を入力するユーザー側の体験としても、
システムへの問い合わせを待つことなく、
すぐに入力ミスが分かった方が快適に感じると思うので、
大変有益なアルゴリズムだと思います。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-about-interfaces" class="outline-3">
<h3 id="2025-01-12-about-interfaces">Typed Racket 実装のインターフェース</h3>
<div class="outline-text-3" id="text-2025-01-12-about-interfaces">
<p>
Typed Racket で実装する際に定義した型や手続きについて紹介します。
</p>

<p>
実際の実装は GitHub の <a href="https://github.com/tojoqk/luhn/blob/d199b5c1db75499a536ccd466d324e1ec6a69b43/luhn.rkt">luhn.rkt</a> に置いてあります。
</p>
</div>
<div id="outline-container-2025-01-12-interface-digit-type" class="outline-4">
<h4 id="2025-01-12-interface-digit-type">Digit 型</h4>
<div class="outline-text-4" id="text-2025-01-12-interface-digit-type">
<p>
折角 Typed Racket を使っているので Digit 型を定義することにしました。
</p>

<p>
手続きに整数のリストを渡すインターフェースにすると、
リストの要素が0から9までの整数になっていない場合には、
入力としては不正なわけです。
</p>

<p>
ただ、実際プログラム書いていてこういう細かいのをエラーにするのは結構面倒だし費用対効果的に微妙となりがちだと思うのですが、
Typed Racket だと気軽に型で入力の制限が可能です。
</p>

<p>
入力値を型で制限しておくと、入力された整数が0から9までの範囲にあるという信頼できる前提にでき思考が軽くなってよいと感じます。
</p>

<p>
以下のように型定義をしました。
</p>

<div class="org-src-container">
<pre class="src src-racket">(define-type Digit (U 0 1 2 3 4 5 6 7 8 9))
(define-predicate digit? Digit)
</pre>
</div>

<p>
かなりごり押し感のある型定義ですが、
Digit は10個しかないのでいいとしましょう。
これで Digit を普通の整数として扱いつつ、0から9までの整数に限定した型が用意できました。
</p>

<p>
また、 <code>digit?</code> 述語も定義しています。
この述語で分岐することで Digit かどうかを判定できます。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-luhn-n-algorithm-interface" class="outline-4">
<h4 id="2025-01-12-luhn-n-algorithm-interface">Luhn アルゴリズムのインターフェース</h4>
<div class="outline-text-4" id="text-2025-01-12-luhn-n-algorithm-interface">
<p>
Luhn アルゴリズムの検証をする際には、
番号の列を一度を <code>Luhn</code> 型の構造体に変換してから扱うことにしました。
</p>
</div>
<ul class="org-ul">
<li><a id="2025-01-12-create-luhn-stracture"></a>Luhn 構造体を作成する<br />
<div class="outline-text-5" id="text-2025-01-12-create-luhn-stracture">
<p>
まず、luhn 構造体を作る方法として次の二つの方法を提供しています。
</p>

<dl class="org-dl">
<dt><code>list-&gt;luhn: (Listof Digit) -&gt; Luhn</code></dt><dd>Digit のリストを Luhn 構造体に変換する手続き</dd>
<dt><code>string-&gt;luhn: String -&gt; (U Luhn False)</code></dt><dd>文字列を Luhn 構造体に変換する手続き</dd>
</dl>

<p>
<code>list-&gt;luhn</code> は確実に <code>Luhn</code> に変換できます。
しかし、文字列の場合は入力に数字以外が含まれているかもしれないので、数字以外の文字が含まれていた場合には <code>#f</code> を返すようにしています。
</p>

<p>
逆に Luhn 構造体から文字列、リストに変換する場合は以下の手続きを使います。
こちらはどちらも失敗する可能性のない手続きです。
</p>

<dl class="org-dl">
<dt><code>luhn-&gt;list: Luhn -&gt; (Listof Digit)</code></dt><dd>Luhn 構造体をリストに変換する手続き</dd>
<dt><code>string-&gt;luhn: Luhn -&gt; String</code></dt><dd>Luhn 構造体を文字列に変換する手続き</dd>
</dl>
</div>
</li>
<li><a id="2025-01-12-ayamari-kensyutu"></a>番号の誤りを検出する<br />
<div class="outline-text-5" id="text-2025-01-12-ayamari-kensyutu">
<p>
以下の手続きで、番号の誤りを検出するようにしました。
</p>

<dl class="org-dl">
<dt><code>luhn-valid?: Luhn -&gt; Boolean</code></dt><dd>番号の不正を検出し、誤りがが検出されなければ <code>#t</code>, 検出された場合は <code>#f</code> を返す</dd>
</dl>

<p>
Luhn 構造体を作成する部分と組合せると次のように使うことで、番号のチェックができます。
</p>

<div class="org-src-container">
<pre class="src src-racket">;; 誤りなしの場合
(luhn-valid? (list-&gt;luhn '(1 4 7 6 3 7))) ; =&gt; #t

;; 誤りありの場合
(luhn-valid? (list-&gt;luhn '(1 4 7 3 6 7))) ; =&gt; #f
</pre>
</div>
</div>
</li>
<li><a id="2025-01-12-add-check-digit"></a>番号にチェックディジットを追加する<br />
<div class="outline-text-5" id="text-2025-01-12-add-check-digit">
<p>
以下の手続きで、番号にチェックディジットを追加できるようにしました。
</p>

<dl class="org-dl">
<dt><code>luhn-add-check-digit: Luhn -&gt; Luhn</code></dt><dd>チェックディジットを追加</dd>
</dl>

<p>
以下のように使用します。
</p>

<div class="org-src-container">
<pre class="src src-racket">(luhn-&gt;list
 (luhn-add-check-digit (list-&gt;luhn '(1 4 7 6 3))))
;; =&gt; '(1 4 7 6 3 7)
</pre>
</div>

<p>
ここまでで、Luhn アルゴリムを扱うのに必要なインターフェースを説明しきりました。
</p>
</div>
</li>
<li><a id="2025-01-12-naze-kono-sekkei"></a>何故 Luhn 構造体を仲介する設計にしたのか<br />
<div class="outline-text-5" id="text-2025-01-12-naze-kono-sekkei">
<p>
最初の実装ではそもそも設計など考えずに、
<code>(Listof Digit)</code> を受けとって <code>Boolean</code> を返す手続きを返そうと思っていました。
</p>

<p>
ただ、この方針だと次の3点が気になったので色々考えた結果 Luhn 構造体を経由するようにしました。
</p>

<ol class="org-ol">
<li>チェックサムを計算するとき、リストが反転している方が望ましいため</li>
<li>チェックディジットを追加するとき、リストが反転している方が望ましいため</li>
<li>リストだけでなく文字列を扱うインターフェースも欲しくなったため
<ul class="org-ul">
<li>文字列を渡す手続きとリストを渡す手続きの二つを作ると無駄が多い
<ul class="org-ul">
<li>一つの手続きにまとめることも可能だが、文字列を渡す場合は失敗する可能性があり、リストを渡す場合は失敗可能性がないので無理に一つにしようとすると複雑になった</li>
</ul></li>
<li>中間構造としては、反転したリストの方がアルゴリズムと相性がよく、一度文字列を Digit のリストに変換してから適用するようにすると、無駄に reverse を実行しないといけないので、リストではなくて中間構造に変換するインターフェースの方がよかった</li>
</ul></li>
</ol>

<p>
上記のように主な理由としては、Luhn アルゴリズムと相性のよい中間構造が、単純な Digit のリストではなくて、反転させたリストの方がよかったのが主要因となって Luhn 構造体を用意しました。
</p>

<p>
Luhn に実は反転したリストが入っているというのは隠蔽したかったので、
<code>luhn</code> モジュールでは Luhn 構造体の中身を外部に公開(<code>provide</code>)していません。
</p>
</div>
</li>
</ul>
</div>
</div>
<div id="outline-container-2025-01-12-about-impl" class="outline-3">
<h3 id="2025-01-12-about-impl">Typed Racket での実装について</h3>
<div class="outline-text-3" id="text-2025-01-12-about-impl">
<p>
では Luhn をどんな感じで実装したのかについて紹介します。
</p>
</div>
<div id="outline-container-2025-01-12-impl-struct" class="outline-4">
<h4 id="2025-01-12-impl-struct"><code>Luhn</code> 構造体の中身</h4>
<div class="outline-text-4" id="text-2025-01-12-impl-struct">
<p>
Luhn 構造体は次のように定義しています。
</p>

<div class="org-src-container">
<pre class="src src-racket">(struct luhn ([rev-digits : (Listof Digit)])
  #:type-name Luhn)
</pre>
</div>

<p>
<code>rev-digits</code> というフィールドのみを持った構造体です。
中間構造としては反転したリストを持った方がやりやすいのでそうしています。
</p>

<p>
<code>list-&gt;luhn</code> は以下のようになっています。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: list-&gt;luhn (-&gt; (Listof Digit) Luhn))
(define (list-&gt;luhn lst)
  (luhn (reverse lst)))
</pre>
</div>

<p>
<code>string-&gt;luhn</code> は、文字列に数字以外が含まれていた場合に対処するため少し複雑になっています。
文字が数字でない場合に <code>#f</code> を返すようにしているだけではあります。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: string-&gt;luhn (-&gt; String (Option Luhn)))
(define (string-&gt;luhn str)
  (call/cc
   (lambda ([return : (-&gt; False Nothing)])
     (luhn
      (for/fold ([rev : (Listof Digit) '()])
                ([c (in-string str)])
        (cond [(digit-char-&gt;digit c) =&gt; (lambda (d) (cons d rev))]
              [else (return #f)]))))))
</pre>
</div>

<p>
(<code>digit-char-&gt;digit</code> の掲載は省略、GitHub で<a href="https://github.com/tojoqk/luhn/blob/d199b5c1db75499a536ccd466d324e1ec6a69b43/luhn.rkt">公開している実装</a>の方を参照してください)
</p>
</div>
</div>
<div id="outline-container-2025-01-12-impl-luhn-valid" class="outline-4">
<h4 id="2025-01-12-impl-luhn-valid"><code>luhn-valid?</code> の実装</h4>
<div class="outline-text-4" id="text-2025-01-12-impl-luhn-valid">
<p>
<code>luhn-valid?</code> は以下の定義になっています。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: luhn-valid? (-&gt; Luhn Boolean))
(define (luhn-valid? lhn)
  (zero? (modulo (luhn-sum lhn) 10)))
</pre>
</div>

<p>
非公開の手続きである <code>luhn-sum</code> メソッドでチェックサムを計算して、10 で割り切れるかを確認します。
</p>

<p>
<code>luhn-sum</code> は次のような感じです。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: luhn-sum (-&gt;* (Luhn) ((Listof (U 1 2))) Natural))
(define (luhn-sum l [scale-list '(1 2)])
  (for/sum : Natural
           ([d : Digit (luhn-rev-digits l)]
            [scale : Natural (in-cycle scale-list)])
    (sum-of-digits (* d scale))))
</pre>
</div>

<p>
luhn アルゴリズムでは、番号の右端から 1, 2, 1, 2 … のサイクルの列を掛け合せた値を使います。
この計算をするのには、事前にリストを反転させておいた方がいいため、 <code>luhn</code> 構造体に入っている反転済みのリストを使っています。
</p>

<p>
番号の各ディジットと scale-list のサイクルを掛けた後、
2桁になる場合は1桁目と2桁目を加算した値を使います。
この計算は <code>sum-of-digits</code> 手続きで実装しています。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: sum-of-digits (-&gt; Natural Natural))
(define (sum-of-digits n)
  (define-values (q r) (quotient/remainder n 10))
  (if (&lt; q 10)
      (+ q r)
      (+ r (sum-of-digits q))))
</pre>
</div>

<p>
この実装では、任意の自然数に対して <code>sum-of-digits</code> を求められるようにしているのですが、 <code>0</code> から <code>19</code> までの整数に対してであれば、
<code>n</code> が <code>9</code> より大きい場合に <code>9</code> を引くという方法でも求められます。
これは、 <a href="https://ja.m.wikipedia.org/wiki/Luhn%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0">Wikipedia の Luhn アルゴリズムのページ</a>に記載されていた実装でこの事実が使われているのをみて知りました。
たしかにそうなのですが、 <code>sum-of-digits</code> という名前を付けて抽象化した以上は 0 から 19 までに限定するのはいかがなものかと思ったので任意の自然数に対して動作するように実装しています。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-impl-luhn-add" class="outline-4">
<h4 id="2025-01-12-impl-luhn-add">チェックディジットを番号の右端に追加する処理の実装</h4>
<div class="outline-text-4" id="text-2025-01-12-impl-luhn-add">
<p>
<code>luhn-add-check-digit</code> の実装は以下の通りです。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: luhn-add-check-digit (-&gt; Luhn Luhn))
(define (luhn-add-check-digit l)
  (luhn (cons (calculate-check-digit l)
              (luhn-rev-digits l))))
</pre>
</div>

<p>
これをみると、やはり反転したリストを中間構造として使うのがよさそうです。
仮に反転していない場合は <code>(append (luhn-digits l) (list (calculate-check-digit l)))</code> のようにしないといけないわけで、要素を一つ追加するのにリストを構成する pair を全部更新するのはちょっとなあという気持ちになると思います。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: calculate-check-digit (-&gt; Luhn Digit))
(define (calculate-check-digit l)
  (let ([sum (luhn-sum l '(2 1))])
    (assert (modulo (- 10 (modulo sum 10)) 10)
            digit?)))
</pre>
</div>

<p>
先程紹介した <code>luhn-sum</code> を再度使っています。
追加するチェックディジットを計算するには、
チェックディジット部分を飛ばしてチェックサムを計算した際に、
何を足したら10で割り切れるかというのを計算する必要があります。
</p>

<p>
チェックディジットを飛ばした場合のチェックサムを計算するために <code>luhn-sum</code> に <code>'(2 1)</code> を渡しています。
こうすることで、右端から 2, 1, 2, 1… で掛け合わせた場合のチェックサムが手に入ります。
(<code>(cons 0 _)</code> をしてから、 <code>luhn-sum</code> に渡してもよかったのですが、無駄にpairを作るのが嫌だと思ったのでそうはしていません)
</p>

<p>
あとは <code>assert</code> の部分についてなのですが、
これは <code>(modulo _ 10)</code> の結果が Natural 型に広がってしまうために書いています。
仮に <code>(digit? (modulo _ 10))</code> が偽の場合は実行時エラーになります。しかし私は <code>(modulo _ 10)</code> の結果は常に <code>Digit</code> だと知っているので <code>assert</code> を書くことにしました。
</p>

<p>
Typed Racket には実験的機能として <a href="https://docs.racket-lang.org/ts-reference/Experimental_Features.html#(part._.Dependent_.Function_.Types)">Dependent Function Type</a> というのがあり、もしかすると <code>0&lt;=n&lt;=9</code> のような <code>n</code> をうまく扱うことができるのかもしれないのですがよく分かっていないのと、それ以前に実験的機能という問題があるのでこのあたりの可能性については深入りしないことにします。
</p>
</div>
</div>
</div>
<div id="outline-container-2025-01-12-pros-cons" class="outline-3">
<h3 id="2025-01-12-pros-cons">Typed Racket で実装してよかったこと/よくなかったこと</h3>
<div class="outline-text-3" id="text-2025-01-12-pros-cons">
</div>
<div id="outline-container-2025-01-12-pros" class="outline-4">
<h4 id="2025-01-12-pros">よかったこと</h4>
<div class="outline-text-4" id="text-2025-01-12-pros">
<ul class="org-ul">
<li>型がつくおかげで細かいエラーの可能性について考慮が不要になってよかった
<ul class="org-ul">
<li>「Digit 以外の整数が渡ってくることがない」など</li>
</ul></li>
<li>Digit 型を定義できること
<ul class="org-ul">
<li>0から9までの整数を表現する型を定義できるのは珍しい</li>
</ul></li>
<li>Racket の for/fold や for/sum などの繰り返し構文が便利で分かりやすい</li>
<li>簡単なテストを実装のそばに書けるのが嬉しい
<ul class="org-ul">
<li><code>module+</code> 構文を使うと実装を書いた後にすぐテストをかけて楽</li>
</ul></li>
<li>型が付いているのでインターフェースの変更時に、試しに動かさなくても壊れている部分を型エラーで全て把握できる</li>
<li>Natural 型が便利、負の整数の可能性を考慮しなくてよいのは最高</li>
</ul>
</div>
</div>
<div id="outline-container-2025-01-12-cons" class="outline-4">
<h4 id="2025-01-12-cons">よくなかったこと</h4>
<div class="outline-text-4" id="text-2025-01-12-cons">
<ul class="org-ul">
<li>Racket に依存すること
<ul class="org-ul">
<li>当然他の Scheme 処理系との互換性はない</li>
</ul></li>
<li>型注釈しないといけない部分としなくてよい部分の違いが分かりにくい場合がある</li>
<li><code>Maybe Boolean</code> 的な構造が欲しい場合に困ると思った
<ul class="org-ul">
<li>最終的な実装ではこの型が不要になる設計にしたが、実装中は悩んでいた</li>
<li>詳細は次の「Typed Racket での失敗の表現をどうするかについて」で言及する</li>
</ul></li>
</ul>
</div>
</div>
</div>
<div id="outline-container-2025-01-12-sippai-hyogen" class="outline-3">
<h3 id="2025-01-12-sippai-hyogen">Typed Racket での失敗の表現をどうするかについて</h3>
<div class="outline-text-3" id="text-2025-01-12-sippai-hyogen">
<p>
今回の実装で最終的には不要となったため、問題にはならなかったのですが、 <code>Boolean</code> を返す手続きで失敗を表現する場合はどうすればいいんだろうと思ったのでその件について話します。
</p>

<p>
Racket では普通失敗を表現するのに  <code>(U &lt;結果の型&gt; False)</code> を使用します。これは結果の型の値か <code>#f</code> のどちらかという意味で、少なくとも Scheme ではこれが便利といえます。
便利だからか Typed Racket では <code>(U &lt;結果の型&gt; False)</code> を <code>(Optionl &lt;結果の型&gt;)</code> とも書けるようになっています。
</p>

<p>
何故これが便利なのかというと <code>cond</code> のようにこのパターンをうまく扱う構文が Scheme の仕様に入っているからです。
</p>

<p>
<code>string-&gt;luhn</code> 手続きを再掲します:
</p>

<div class="org-src-container">
<pre class="src src-scheme">(: string-&gt;luhn (-&gt; String (Option Luhn)))
(<span class="org-keyword">define</span> (<span class="org-function-name">string-&gt;luhn</span> str)
  (<span class="org-keyword">call/cc</span>
   (<span class="org-keyword">lambda</span> ([return : (-&gt; False Nothing)])
     (luhn
      (for/fold ([rev : (Listof Digit) '()])
                ([c (in-string str)])
        (<span class="org-keyword">cond</span> [(digit-char-&gt;digit c) =&gt; (<span class="org-keyword">lambda</span> (d) (cons d rev))]
              [else (return #f)]))))))
</pre>
</div>


<p>
<code>digit-char-&gt;digit</code> は <code>(-&gt; Char (Option Digit))</code> という型の手続きで、 <code>Digit</code> の値か <code>#f</code> のどちらかを返します。
で、 <code>Digit</code> だった場合は <code>=&gt;</code> の右にある手続きに結果を渡して呼び出して、そうでなければ次の条件を見るというものです。
</p>

<p>
Scheme 標準の手続きでも <code>string-&gt;number</code> のような手続きでは、
失敗したら <code>#f</code> で、成功したら 数が返るようなものがあり、
<code>#f</code> は Scheme で失敗を表現するよいツールとなっています。
</p>

<p>
ただ、場合によっては Boolean もしくは失敗の意味ではない <code>#f</code> を返す手続きが失敗するというケースも考えられるわけです。
この場合は困るということで、今回考えた回避策を紹介します。
</p>
</div>
<div id="outline-container-2025-01-12-shippai-example" class="outline-4">
<h4 id="2025-01-12-shippai-example">Boolean を返す失敗する手続きの例</h4>
<div class="outline-text-4" id="text-2025-01-12-shippai-example">
<p>
文字列を渡して、luhn アルゴリズムで検証する手続きを実装すると考えてみましょう。
</p>

<p>
この手続きはどういう型にするのがいいでしょうか。
文字列に数字以外がある場合と、
luhn アルゴリズムで検証した結果誤りがあった場合では、
失敗の意味合いが異なってきます。
前者はプログラムが期待していない入力値エラーという意味で、
後者はluhnアルゴリズムの結果として誤りを発見したという意味です。
</p>

<p>
luhn アルゴリムで検証することが主目的であれば、
文字列に数字以外がある場合はその計算の目的を果たす前に失敗したということなので、計算の失敗を表現しないといけません。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-reigai-wo-tukau" class="outline-4">
<h4 id="2025-01-12-reigai-wo-tukau">例外を使う方法</h4>
<div class="outline-text-4" id="text-2025-01-12-reigai-wo-tukau">
<p>
シンプルに例外を放ってしまうというのも一つの選択肢です。
Racket には Java の throws みたいな機能がなく、
手続きがどの例外を放つ可能性があるのかということを適切に把握できるわけではないためあまり使いたくない気がしています。
</p>

<p>
例外を使う場合はドキュメント作成の負荷が上がるし、
利用者にドキュメント参照の負荷をかけることになるのでなるべく避けたい気がします。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-use-maybe" class="outline-4">
<h4 id="2025-01-12-use-maybe">Maybe を使う方法</h4>
<div class="outline-text-4" id="text-2025-01-12-use-maybe">
<p>
Haskell などで採用されているのと同じ Maybe 型を定義するという方法です。
</p>

<p>
Racket には代数的データ型はない(と思うの)ですが、次のように構造体を定義すれば Maybe をエミュレートできます。
</p>

<div class="org-src-container">
<pre class="src src-racket">(struct (A) just ([value : A])
  #:type-name Just)
(struct none ()
  #:type-name None)
(define-type (Maybe A) (U (Just A) None))
</pre>
</div>

<p>
これなら <code>(Maybe Boolean)</code> という構造を作れますし、Maybe をネストすることも可能です。
</p>

<p>
しかし、前述したような <code>cond</code> の <code>=&gt;</code> のような Racket
標準にある便利な構文が使えるわけでもないので、
Racket の標準的な実装方法から大きく外れる問題があります。
これをうまく扱うライブラリが適切に整っていないと別に便利とはいえないですし、揃っていたとしても Typed Racket 標準から大きく外れて特定のライブラリに深く依存する感じになるのが嫌です。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-use-failure-cont" class="outline-4">
<h4 id="2025-01-12-use-failure-cont">失敗継続を使う方法</h4>
<div class="outline-text-4" id="text-2025-01-12-use-failure-cont">
<p>
失敗継続を使うという方法があります。
この方法で実装する場合はこんな感じになります。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: luhn-string-valid? (All (A) (-&gt; String (-&gt; A) (U A Boolean))))
(define (luhn-string-valid? str fail)
  (cond [(string-&gt;luhn str) =&gt; luhn-valid?]
        [else (fail)]))
</pre>
</div>

<p>
失敗した場合に継続する処理を、
ライブラリのユーザー側で決めてから <code>luhn-string-valid?</code> を使うという方法です。
ちょっと気になるのは、 <code>Boolean</code> を返すとは限らないのに <code>?</code> を使うのっていいのだろうかというところで少し微妙な感じがします。
</p>

<p>
以下のように型を変更すれば、失敗した場合は <code>(fail)</code> が値を返さないようにすることを利用者に強要することも可能なのですが、
失敗継続に何を渡すかには好みがある気がしていて、戻り値の型を <code>Boolean</code> にするためだけにこういった無理強いをするのはどうなのかなと思います。
</p>

<div class="org-src-container">
<pre class="src src-racket">(: luhn-string-valid? (-&gt; String (-&gt; Nothing) Boolean))
(define (luhn-string-valid? str fail)
  (cond [(string-&gt;luhn str) =&gt; luhn-valid?]
        [else (fail)]))
</pre>
</div>

<p>
この場合は失敗継続は値を返してはならないので、
<code>fail</code> 手続きの中で例外を発生させるか、 <code>call/cc</code> で外に脱出させるかといったことを利用者に強制することが可能です。
</p>

<p>
しかし、この方法でも値を返さないことがあるのに述語というのはおかしいので、そんな副作用のある変な述語は述語じゃないということでやはり名前から <code>?</code> は取った方がいいような気がします。
</p>
</div>
</div>
<div id="outline-container-2025-01-12-not-define" class="outline-4">
<h4 id="2025-01-12-not-define">失敗する可能性のある Boolean を返す手続きは定義しない</h4>
<div class="outline-text-4" id="text-2025-01-12-not-define">
<p>
これは、今回の <code>luhn</code> モジュールで採用した戦略です。
<code>luhn-string-valid?</code> のような Boolean を返すが失敗する可能性があるという種類の手続きをそもそも定義しなければ問題は解決したといえます。
</p>

<p>
結局、失敗する可能性のある Boolean を返す手続きというのは、
なんらかの意味で副作用のある変な述語であり、
そもそも何か設計がおかしいのかもしれません。
</p>

<p>
<b>計算結果の構造体を定義して、
その結果の構造体に対しての述語手続きを用意する方法の方がうまい設計だといえるのかもしれないです。</b>
</p>

<p>
いつでもこの方法が取れるかについてはよく分からないのですが、
この方法を採用した結果、設計がより綺麗になるのであれば、基本的にはこれでいいのかなという感じがします。
</p>
</div>
</div>
</div>
<div id="outline-container-2025-01-12-owarini" class="outline-3">
<h3 id="2025-01-12-owarini">おわりに</h3>
<div class="outline-text-3" id="text-2025-01-12-owarini">
<p>
私の趣味で実際に Luhn アルゴリズムを使いたいと思うことはあまりなさそうですが、書いてみて設計を検討したのはよい体験でした。
私的な自分の名刺を作成する際に、それぞれの名刺にユニークな番号を振っておいて、渡した相手に ID を振って何かの機会に入力してもらうみたいなことはギリギリありえるかもしれません。
</p>

<p>
久々に Typed Racket でプログラムを書いてみて、
「やはり Typed Racket はよいな」と思いました。
自分が Lisp を強く好んでいるというバイアスはかかっていますが、
なんというか丁度よく便利な型システムという感じがします。
万能なわけではないですが、今回定義した Digit 型のように Integer
の一部分を型にできるのは結構嬉しいです。
</p>

<p>
今回私が定義した Digit 型は入力を制限することにしか役立たず演算が絡むとすぐに広い型になってしまって面倒なことになりますが、
Typed Racket で定義されている <code>Natural</code> 型は本当に便利です。
<code>Natural</code> の値を <code>zero?</code> で分岐すると
<code>Zero</code> と <code>Exact-Positive-Integer</code> に分かれ、
<code>Exact-Positive-Integer</code> から 1 を引くと
<code>Natural</code> 型になることを活用することで、
<code>factorial</code> や <code>fibonacci</code> のような再帰手続きも普通に定義できますし、
<code>Natural</code> 型まわりの計算は Typed Racket 側でよくサポートされているので計算が絡んでも <code>Integer</code> 型になりくいのでだいぶ便利です。
負の整数の可能性が邪魔なことってプログラミングをしているとかなりあるので、結構嬉しいのではないかと思います。
とにかく Typed Racket は結構便利だというのが私の感覚なので、使ってみようと思っていただければ幸いです。
</p>

<p>
一回記事を書いてみて振り返った結果、
「失敗する可能性のある Boolean を返す手続きは定義しない」という方針が今回に限らず設計をよくする大切なヒントっぽいことに気づけてよかったです。
設計・実装時ではなんとなくの思いつきでやっていたことですが、
記事として書くことで言語化し、問題を整理することで気づきを得られたのだと思うので、今後も積極的に記事を書いていこうかなと思います。
</p>
</div>
</div>
]]></description>
</item>
<item>
<title>「末尾再帰への書き換え」の弊害について</title>
<link>https://www.tojo.tokyo/posts/stop-rewriting-to-tail-recursion.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/stop-rewriting-to-tail-recursion.html</guid>
<pubDate>Wed, 25 Dec 2024 22:55:00 +0000</pubDate>

<description><![CDATA[<div id="outline-container-2024-12-25-hajimeni" class="outline-3">
<h3 id="2024-12-25-hajimeni">はじめに</h3>
<div class="outline-text-3" id="text-2024-12-25-hajimeni">
<p>
<a href="https://qiita.com/advent-calendar/2024/lisp">Lisp Advent Calendar 2024</a> の25日目の記事です。
</p>

<p>
美しい再帰手続き(再帰関数)を
分かりにくい末尾再帰(反復アルゴリズム)に変換することなく、
そのままの美しさを保つことを推奨します。
</p>

<p>
深くネストした再帰に起因するスタックオーバーフローは、
プログラミング言語の処理系が課す厳しい制約であり、
無条件に認めるべき前提ではありません。
</p>

<p>
深くネストした再帰をサポートしている処理系であれば、
可読性に優れた美しい再帰手続きが書けます。
</p>

<p>
一般的なタイトルを付けましたが、
本記事では Scheme の処理系についてのみ調査しています。
</p>


<p>
本当は Scheme に限定した記事を書くつもりだったのですが、
主題自体は一般的な内容であり、
スタックオーバーフローするから末尾再帰にすることを推奨する書籍や記事が無数にあるため、
意図的に一般化したタイトルとしました。
</p>

<p>
本記事は過去記事の「<a href="https://www.tojo.tokyo/posts/guile-recursion.html">Guile ではスタック溢れを気にせず再帰しよう</a>」
を一般化したタイトルに変更し、再帰の美しさの説明を強化したバージョンです。
</p>
</div>
</div>
<div id="outline-container-2024-12-25-naniga-yoinoka" class="outline-3">
<h3 id="2024-12-25-naniga-yoinoka">再帰の何がよいのか</h3>
<div class="outline-text-3" id="text-2024-12-25-naniga-yoinoka">
<p>
再帰手続きは再帰的な構造したデータを対象に
計算を行なうのに方法です。
</p>

<p>
再帰的なデータ構造の処理を再帰で扱うと、
宣言的な記述で処理を定義でき、
停止性の条件を満たしつつ、
正しく式を書き換えるだけで再帰関数を定義できます。
</p>

<p>
読む場合も式の書き換えが正しいことに
納得すればそれだけで再帰手続きを理解できます。
</p>

<p>
これが再帰の力であり美しさです。
</p>

<p>
再帰手続きの何がよいのかを説明している章であるため、
再帰が美しく分かりやすい記述であると納得している方は、
この章は飛ばしてしまって問題ありません。
</p>
</div>
<div id="outline-container-2024-12-25-data-structure" class="outline-4">
<h4 id="2024-12-25-data-structure">再帰的なデータ構造</h4>
<div class="outline-text-4" id="text-2024-12-25-data-structure">
<p>
まず再帰的なデータ構造について本記事で扱うものを紹介します。
</p>
</div>
<ul class="org-ul">
<li><a id="2024-12-25-list"></a>リスト<br />
<div class="outline-text-5" id="text-2024-12-25-list">
<p>
Scheme におけるリストは次のように定義できます。
</p>

<ul class="org-ul">
<li>空リストはリストである</li>
<li>cdr部がリストのペアはリストである</li>
</ul>
</div>
<ul class="org-ul">
<li><a id="2024-12-25-pair"></a>ペアとは<br />
<div class="outline-text-6" id="text-2024-12-25-pair">
<p>
Scheme のペアには <code>car</code> 部と
<code>cdr</code> 部があり、それぞれ手続き <code>car</code>, <code>cdr</code>
で取り出すことができます。
<code>car</code> 部が <code>x</code> で <code>cdr</code> 部が <code>y</code> のペアは
<code>(cons x y)</code> で構成することができます。
</p>

<p>
つまり <code>(car (cons x y))</code> は <code>x</code> で、
<code>(cdr (cons x y))</code> は <code>y</code> です。
</p>

<p>
ペアがリストである場合は <code>car</code> は、
リストの最初の要素を求める手続きで、
<code>cdr</code>
はリストの最初を取り除いたリストと求める手続きでもあります。
</p>
</div>
</li>
</ul>
</li>
<li><a id="2024-12-25-nats"></a>自然数<br />
<div class="outline-text-5" id="text-2024-12-25-nats">
<p>
ここでは自然数は <code>0</code> から始まるとします。
自然数も次のように再帰的にデータ構造として定義できます。
(数学的に厳密な自然数の定義については「ペアノ公理系」を参照してください)
</p>

<ul class="org-ul">
<li><code>0</code> は自然数である</li>
<li>自然数の「次の」数も自然数である</li>
</ul>
</div>
</li>
</ul>
</div>
<div id="outline-container-2024-12-25-delactive" class="outline-4">
<h4 id="2024-12-25-delactive">再帰手続きは宣言的記述</h4>
<div class="outline-text-4" id="text-2024-12-25-delactive">
<p>
綺麗な再帰手続きは、
計算の手順を記述したものとしてではなく、
宣言的な定義として読めます。
</p>

<p>
たとえばリストを連結する手続きを
Scheme で書いてみましょう。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-append</span> lst1 lst2)
  (<span class="org-keyword">if</span> (not (pair? lst1))
      (<span class="org-keyword">if</span> (null? lst1)
          lst2
          (error <span class="org-string">"my-append: &#20837;&#21147;&#12399;&#30495;&#12522;&#12473;&#12488;&#12391;&#12394;&#12369;&#12428;&#12400;&#12394;&#12426;&#12414;&#12379;&#12435;"</span> lst1))
      (cons (car lst1)
            (my-append (cdr lst1) lst2))))
</pre>
</div>

<p>
この定義では <code>lst1</code> の値によって3つの場合に分けて、
それぞれ <code>(my-append lst1 lst2)</code> をどのように置き換えるかということを記述しています。
</p>

<p>
ここでは、二つの式「 <code>x</code> と <code>y</code> が等しい」を <code>(equal? x y)</code>
、「 <code>p</code> ならば <code>q</code> 」を <code>(implies p q)</code> と表現することにします。
</p>

<div class="org-src-container">
<pre class="src src-scheme"><span class="org-comment-delimiter">;; </span><span class="org-comment">1. lst1 &#12364;&#12506;&#12450;&#12391;&#12394;&#12367;&#12363;&#12388; lst1 &#12364; null? (&#31354;&#12522;&#12473;&#12488;)&#22580;&#21512;
</span><span class="org-comment-delimiter">;; </span><span class="org-comment">(null? lst1) &#12424;&#12426; lst1 &#12399; '()
</span>(implies (<span class="org-keyword">and</span> (not (pair? lst1))
              (null? lst1))
         (equal? (my-append '() lst2) lst2))

<span class="org-comment-delimiter">;; </span><span class="org-comment">2. lst1 &#12364;&#12506;&#12450;&#12391;&#12394;&#12367;&#31354;&#12522;&#12473;&#12488;&#12391;&#12418;&#12394;&#12356;&#12392;&#12365;&#12399;&#12456;&#12521;&#12540;
</span><span class="org-comment-delimiter">;; </span><span class="org-comment">lst1 &#12399;&#12522;&#12473;&#12488;&#12391;&#12394;&#12356;&#12383;&#12417;&#20837;&#21147;&#12456;&#12521;&#12540;&#12392;&#12377;&#12427;
</span>(implies (<span class="org-keyword">and</span> (not (pair? lst1))
              (not (null? lst1)))
         (equal? (my-append lst1 lst2)
                 (error <span class="org-string">"my-append: &#24341;&#25968;&#12399;&#30495;&#12522;&#12473;&#12488;&#12391;&#12394;&#12369;&#12428;&#12400;&#12394;&#12426;&#12414;&#12379;&#12435;"</span> lst1)))

<span class="org-comment-delimiter">;; </span><span class="org-comment">3 lst1 &#12364;&#12506;&#12450;&#12398;&#12392;&#12365;&#12289;(my-append lst1 lst2) &#12392; (cons (car lst1) (my-append (cdr lst1) lst2)) &#12399;&#31561;&#12375;&#12356;
</span>(implies (pair? lst1)
         (equal? (my-append lst1 lst2)
                 (cons (car lst1)
                       (my-append (cdr lst1) lst2))))
</pre>
</div>

<p>
1番目と2番目は自明です。
1番目は空リストと他のリストを連結した場合は変化しないということを意味しています。
2番目は <code>lst1</code> がリストではなかった場合です。
この場合は引数がリストであるという前提に違反しているのでエラーでよいでしょう。
</p>

<p>
問題は3番目です。
<code>equal?</code> の部分が真でよいのか考えてみましょう。
3番目のケースは <code>lst1</code> を先頭の要素 <code>(car lst1)</code> と
残りのリスト <code>(cdr lst1)</code> に分割しています。
私が想像しているリストの連結では <code>lst1</code> がペアなら
<code>(my-append lst1 lst2)</code> もペアであるです。
</p>

<p>
そのため、両辺を <code>car</code>, <code>cdr</code> で二つに分けてそれぞれ考えましょう。
</p>

<div class="org-src-container">
<pre class="src src-scheme"><span class="org-comment-delimiter">;; </span><span class="org-comment">1. lst1 &#12392; lst2 &#12434;&#36899;&#32080;&#12375;&#12383;&#12392;&#12365;&#12289;&#26368;&#21021;&#12398;&#35201;&#32032;&#12399; lst1 &#12398;&#26368;&#21021;&#12398;&#35201;&#32032;&#12392;&#31561;&#12375;&#12356;
</span>(implies (pair? lst1)
         (equal? (car (my-append lst1 lst2))
                 (car lst1)))

<span class="org-comment-delimiter">;; </span><span class="org-comment">2. lst1 &#12392; lst2 &#12434;&#36899;&#32080;&#12375;&#12383;&#12392;&#12365;&#20808;&#38957;&#12434;&#38500;&#12356;&#12383;&#12522;&#12473;&#12488;&#12399;
</span><span class="org-comment-delimiter">;; </span><span class="org-comment">lst1 &#12398;&#20808;&#38957;&#12434;&#38500;&#12356;&#12383;&#12522;&#12473;&#12488;&#12392; lst2 &#12434;&#36899;&#32080;&#12375;&#12383;&#12418;&#12398;&#12392;&#31561;&#12375;&#12356;
</span>(implies (pair? lst1)
         (equal? (cdr (my-append lst1 lst2))
                 (my-append (cdr lst1) lst2)))
</pre>
</div>

<p>
以上の二つですが、 <code>(my-append lst1 lst2)</code> が「リストの連結」
を意味しているのであれば、その性質から真であるべきです。
このように定義は意図した通りであると確認できました。
</p>

<p>
しかし、再帰的定義では単に書き換えが意図したものであれば、
いいわけではないことに注意が必要です。
再帰手続きはうまく定義しないと計算が終了しない可能性があります。
計算が終了しないのは致命的なバグですので、
停止することを確認する必要があります。
</p>

<p>
これを確認するには手続き内の全ての再帰呼び出しについて確認する必要があります。
今回は <code>(my-append (cdr lst1) lst2)</code> にフォーカスするとよいです。
<code>my-append</code> の一つ目の引数では、
リストの要素数を一つ減らしていることに注目してください。
リスト要素数は減少を繰り返すといずれ必ず長さの最小値である0に到達します。
長さが0のリストは <code>pair?</code> ではなく <code>pair?</code> でない場合は再帰呼び出しをしないため、
<code>my-append</code> は必ず停止します。
</p>

<p>
以上のように停止性についての考慮は必要ではありますが、
それさえ確認ができれば再帰手続きの正当性を確かめるのに必要なのは、
それぞれのケースにおいて式の書き換えが妥当であるということだけです。
</p>

<p>
計算量に対する考察も必要ではあるのですが、
この式が何やっているかという点については、
式を見れば分かるという程度の性質のものであり、
計算の流れを追いかけないと分からないというものではないのです。
</p>

<p>
これこそが再帰による記述の強みです。
再帰は理解が容易で検証が簡単なプログラムの書き方なのです。
</p>

<p>
「末尾再帰への書き換え」
は再帰アルゴリズムの優れた性質を大きく損なうし、
計算効率上の利点もないケースが多くあるので、
必要ないならやめた方がいいというのが本記事の主張です。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-25-rewriting" class="outline-3">
<h3 id="2024-12-25-rewriting">末尾再帰への書き換えとは何か</h3>
<div class="outline-text-3" id="text-2024-12-25-rewriting">
<p>
末尾再帰への書き換えとは、
以上のように自然に書いた再帰関数を、
スタックオーバーフローのリスクを回避するために、
末尾再帰に書き換えることです。
</p>

<p>
たとえば、リストの要素をそれぞれ手続き <code>proc</code>
で変換したリスト作成する <code>my-map</code> 手続きを考えてみましょう。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-map</span> proc lst)
  (<span class="org-keyword">if</span> (not (pair? lst))
      '()
      (cons (proc (car lst))
            (my-map proc (cdr lst)))))
</pre>
</div>

<p>
も先程と同じように以下のように、
リスト を <code>car</code> と <code>cdr</code> に分けて確認すれば、
正しく定義できていることを確認できます。
(<code>(not (pair? lst))</code> の場合は自明のため省略)
</p>

<div class="org-src-container">
<pre class="src src-scheme">(implies (pair? lst)
         (equal? (car (my-map f lst))
                 (f (car lst))))

(implies (pair? lst)
         (equal? (cdr (my-map f lst))
                 (my-map f (cdr lst))))
</pre>
</div>

<p>
しかし、
多くの書籍や記事ではこのまま書き方では問題があるとしています。
<code>lst</code> のリストが長い場合に、
スタックオーバーフローが発生して実行時エラーとなる可能性があるからです。
この場合は末尾呼び出しが最適化されることが前提となりますが、
以下のように書き換えるよう推奨されます(ループでもよいです)。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-map-tail</span> proc lst)
  (%my-map-tail proc lst '()))

(<span class="org-keyword">define</span> (<span class="org-function-name">%my-map-tail</span> proc lst acc)
  (<span class="org-keyword">if</span> (not (pair? lst))
      (reverse acc)
      (%my-map-tail proc
                    (cdr lst)
                    (cons (proc (car lst))
                          acc))))
</pre>
</div>

<p>
さて、この <code>%my-map-tail</code> についていままでと同様に考えてみましょう
</p>

<p>
<code>(not (pair? lst))</code> の場合は <code>(reverse acc)</code> です。
まず、この時点で「 <code>acc</code> って何？」と思いませんか？
これは <code>my-map</code> が <code>(not (pair? lst))</code> の場合について、
解説が省略されるほど自明であったのとは対照的です。
<code>acc</code> を理解するには、 <code>(pair? lst)</code> の場合について先に考える必要があります。
</p>

<p>
<code>(pair? lst)</code> の場合はこうなります。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(implise (pair? lst)
         (equal? (%my-map-tail proc lst acc)
                 (%my-map-tail proc
                               (cdr lst)
                               (cons (proc (car lst))
                                     acc))))
</pre>
</div>

<p>
いままでと同様に <code>car</code> と <code>cdr</code> で分けてみましょう。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(implise (pair? lst)
         (equal? (car (%my-map-tail proc lst acc))
                 (car (%my-map-tail proc
                                    (cdr lst)
                                    (cons (proc (car lst))
                                          acc)))))

(implise (pair? lst)
         (equal? (cdr (%my-map-tail proc lst acc))
                 (cdr (%my-map-tail proc
                                    (cdr lst)
                                    (cons (proc (car lst))
                                          acc)))))
</pre>
</div>

<p>
いままではこれで簡単に理解できたのに、
<code>car</code> と <code>cdr</code> で場合分けしてみても何も分かりませんでした。
このアプローチは末尾再帰に変換したアルゴズムの前には無力です。
</p>

<p>
この手続きを理解するには、
引数の状態の変化に着目する必要があります。
</p>

<p>
再帰呼び出しのたびに、 引数の状態は次のように変化していきます。
</p>
<dl class="org-dl">
<dt><code>lst</code></dt><dd>先頭要素を取り除く</dd>
<dt><code>acc</code></dt><dd><code>lst</code> の先頭要素に手続き <code>proc</code> を呼び出した結果を <code>acc</code> の先頭に追加</dd>
</dl>

<p>
これを繰り返すと、 <code>lst</code> が空になったときには、
<code>acc</code> に最初の <code>lst</code> に入っていた要素が全て <code>proc</code> の計算結果になって
入っています。 ただし、順番は逆順となっています。
逆になっていると困るということで、
最後に <code>reverse</code> 手続きで順番を元に戻しているのです。
</p>

<p>
このアルゴリズは以上のように「計算の流れ」を追跡しないと理解できません。
特に <code>(pair? lst)</code> の場合とそうでない場合が独立しておらず、
相互に依存しあっているので複雑です。
</p>

<p>
実は <code>my-map</code> と <code>%my-map-tail</code> が同じ計算をすることは、
数学的帰納法のテクニックを使うことで証明可能です。
なので、「計算の流れ」を追跡しなくても、 <code>my-map</code>
と同じであることを示せば理解可能なのですが、
だからといってこれが一目みて確かだと思えるようなものではないという
のは間違いありません。
</p>

<p>
よく言われる「末尾再帰への書き換え」は、
明らかに正しかった再帰的な定義を一見して正しいのかよく分からない
複雑な記述へと書き換えているのです!
</p>
</div>
<div id="outline-container-2024-12-25-tail-recursin-is-loop" class="outline-4">
<h4 id="2024-12-25-tail-recursin-is-loop">末尾再帰への書き換えはループへの書き換えである</h4>
<div class="outline-text-4" id="text-2024-12-25-tail-recursin-is-loop">
<p>
「末尾再帰への書き換え」と言われますが、
やっていることはループへの書き換えです。
</p>

<p>
Scheme には名前付きletという構文があり、
以下のようにも書けます。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-map-tail</span> proc lst)
  (<span class="org-keyword">let</span> <span class="org-function-name">loop</span> ((lst lst)
             (acc '()))
    (<span class="org-keyword">if</span> (not (pair? lst))
        (reverse acc)
        (loop proc
              (cdr lst)
              (cons (proc (car lst))
                    acc)))))
</pre>
</div>

<p>
これもまた末尾再帰なのですが、
ほぼほぼループ構文みたいな記述になります。
なお、名前付き <code>let</code>
を使って末尾再帰でない再帰手続きを書くことも可能なので
そこは注意してください。
</p>

<p>
さらに、Scheme の <code>do</code> という繰り返し用の構文を使って
書くこともできます。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-map-tail</span> proc lst)
  (<span class="org-keyword">do</span> ((lst lst (cdr lst))
       (acc '() (cons (proc (car lst))
                      acc)))
      ((not (pair? lst)) (reverse acc))))
</pre>
</div>

<p>
Scheme では <code>do</code> も実態としては末尾再帰をしているのですが、
こちらはより繰り返し機能にフォーカスした構文となっています。
</p>

<p>
これら全部同じです。
末尾再帰への書き換えとかいっていますが、
ようするにループへの書き換えです。
末尾再帰への書き換えの実態はループへの書き換えです。
</p>

<p>
繰り返しよりも末尾再帰の方が好きなんだ！
と思う方もいるかもしれませんが、
残念ながらこの使い方においてはループと同じです。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-25-performance" class="outline-3">
<h3 id="2024-12-25-performance">計算の効率はどうなのか</h3>
<div class="outline-text-3" id="text-2024-12-25-performance">
<p>
「末尾再帰の方が計算効率がよい」ために、
末尾再帰を採用するのであって、スタックオーバーフローの
回避のためだけではないという意見もあるでしょう。
</p>

<p>
前述した <code>my-map</code> と <code>%my-map-tail</code> を比較します。
この二つではどちらが効率的でしょうか？
(ここでは <code>proc</code> 呼び出しの処理は無視して比較します)
</p>

<p>
なお、 <code>my-map</code> と <code>%my-map-tail</code> の計算量の違いというのは、
わずかでありオーダー記法で比較しても無意味なレベルなので
空間使用量やステップ数を推定してどちらが速そうか検討します。
</p>

<p>
<code>my-map</code> を再掲します。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-map</span> proc lst)
  (<span class="org-keyword">if</span> (not (pair? lst))
      '()
      (cons (proc (car lst))
            (my-map proc (cdr lst)))))
</pre>
</div>

<p>
<code>my-map</code> を再帰呼び出しをする度に、
呼び出し元を記憶するためにコールスタックに push する必要があります。
また、残りの処理ではコールスタックを pop しながら戻り、
それぞれ残りの処理で <code>cons</code> していきます。
</p>

<p>
<code>%my-map-tail</code> を再掲します。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-map-tail</span> proc lst)
  (%my-map-tail proc lst '()))

(<span class="org-keyword">define</span> (<span class="org-function-name">%my-map-tail</span> proc lst acc)
  (<span class="org-keyword">if</span> (not (pair? lst))
      (reverse acc)
      (%my-map-tail proc
                    (cdr lst)
                    (cons (proc (car lst))
                          acc))))
</pre>
</div>

<p>
手続きの中では <code>%my-map-tail</code> は末尾呼び出しされているので、
Scheme では呼び出した後に戻ってきません。
言語処理系はコントロールスタックを必要としません。
その代わりに <code>acc</code> に対して <code>cons</code> しています。
この <code>acc</code> 変数への <code>cons</code> がスタックを積む代わりの操作となっています。
<code>lst</code> が空になったときに 全部の計算結果が <code>acc</code> に入ります。
<code>my-map</code> のときは <code>lst</code> が空になった後は、
「残りの計算」を開始しましたが、
<code>%my-map-tail</code> では <code>lst</code> が空になった時点で最後のステップとなります。
しかし、 <code>acc</code> は期待しているリストとは順番が逆になるので、
リストは <code>reverse</code> で反転させないといけません。
このとき <code>acc</code> の長さ分のペアが作られます(<code>cons</code> されます)。
</p>

<p>
<code>lst</code> の要素数を <code>n</code> として比較してみると、
<code>my-map</code> ではコールスタックに積む操作が、
<code>n</code> 回で <code>cons</code> が <code>n</code> 回なのに対し、
<code>%my-map-tail</code> では <code>cons</code> が <code>2n</code> 回です。
<code>my-map</code> の方が通常メモリ確保済みのスタックを使えるのに対して、
<code>%my-map-tail</code> ではヒープ領域を確保しながら
メモリ割り当てしないといけないので遅そうです。
</p>

<p>
なお、 <code>(srfi 1)</code> の線形更新版の <code>reverse!</code>
を使用すれば新規にペア作る必がない分 <code>%my-map-tail</code>
の方が有利になります。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">%my-map-tail/reverse!</span> proc lst acc)
  (<span class="org-keyword">if</span> (not (pair? lst))
      (reverse! acc)
      (%my-map-tail/reverse! proc
                             (cdr lst)
                             (cons (proc (car lst))
                                   acc))))

(<span class="org-keyword">define</span> (<span class="org-function-name">my-map-tail/reverse!</span> proc lst)
  (%my-map-tail/reverse! proc lst '()))
</pre>
</div>

<p>
この場合 <code>reverse!</code> では新規の <code>cons</code> もしないし、
<code>reverse!</code> は末尾再帰で実装できるのでスタックも使わないため最も速そうです。
</p>

<p>
一見問題なさそうではありますが、
Scheme だと継続安全(continuation-safe)ではなくなるという問題があります(
continuation-safe は安全はGuile のドキュメントの<a href="https://www.gnu.org/software/guile/manual/html_node/Stack-Overflow.html#Stack-Overflow">6.26.3.4 Stack Overflow</a> から引用)。
<code>my-map-tail</code> で <code>reverse!</code> を使うと、
<code>acc</code> が壊れます。Scheme だと proc の中の継続が外から呼ばれる可能性があり、
<code>acc</code> の副作用が検出可能であり、
こういった破壊的な手続きの使用には注意が必要です。
</p>

<p>
また、Racket では変更不能なペアを使うため、
そもそも <code>reverse!</code> を定義できないという問題があります。
</p>
</div>
</div>
<div id="outline-container-2024-12-25-somosomo" class="outline-3">
<h3 id="2024-12-25-somosomo">そもそも「末尾再帰への書き換え」とはいえないケース</h3>
<div class="outline-text-3" id="text-2024-12-25-somosomo">
<p>
アルゴリズムが全然違うので、
本記事で解説している
「末尾再帰への書き換え」とは異なるケースについて説明します。
</p>
</div>
<div id="outline-container-2024-12-25-somosomo-fib" class="outline-4">
<h4 id="2024-12-25-somosomo-fib">フィボナッチ数の計算</h4>
<div class="outline-text-4" id="text-2024-12-25-somosomo-fib">
<p>
末尾再帰でないフィボナッチ数の計算を
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">fib</span> n)
  (<span class="org-keyword">cond</span> ((&lt;= n 0) 0)
        ((= n 1) 1)
        (<span class="org-keyword">else</span> (+ (fib (- n 1))
                 (fib (- n 2))))))
</pre>
</div>

<p>
として、末尾再帰版を
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">fib-tail</span> n a b)
  (<span class="org-keyword">if</span> (&lt;= n 0)
      a
      (fib-tail (- n 1) b (+ a b))))
</pre>
</div>

<p>
とするものがあります。
</p>

<p>
一目瞭然ですが、両者では計算方法がまったく違います。
そもそも <code>fib</code> は木構造的な再帰をしているのに、
<code>fib-tail</code> は繰り返し処理になっています。
</p>

<p>
このように全然違うものについて比較して、
末尾再帰の方がよいとするのは
本記事の主題とは関係のない話です。
</p>
</div>
</div>
<div id="outline-container-2024-12-25-somosomo-reverse" class="outline-4">
<h4 id="2024-12-25-somosomo-reverse">非末尾再帰版の <code>reverse</code></h4>
<div class="outline-text-4" id="text-2024-12-25-somosomo-reverse">
<p>
これは Lisp のリストに慣れていないとやってしまう
可能性のある大きな間違いです。
これは、アルゴリズムが致命的な欠陥を抱えているという問題であり、
「末尾再帰に書き換える」という話ではありません。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">heavy-reverse</span> lst)
  (<span class="org-keyword">if</span> (not (pair? lst))
      '()
      (append (heavy-reverse (cdr lst))
              (list (car lst)))))
</pre>
</div>

<p>
この定義は論理的には問題がなく、
意図した通りに <code>lst</code> を反転したリストを求めます。
</p>

<p>
しかし、リストの特性を考慮すると致命的な欠陥となります。
再帰手続きの帰納部に <code>(append x (list e))</code>
という構造がの式があるのはとてもよくないです。
</p>

<p>
<code>cons</code> は一つペアを作る手続きなのに対し、
<code>(append x y)</code> は <code>(legnth x)</code> 個のペアを作る操作です。
この操作を再帰的に適用してまうと、
大量のペアを作成することとなり大変なことになってしまいます。
</p>

<p>
Scheme のリストは左側に要素を追加するのと右側に要素を追加するのは、
まったく異なるので気をつけましょう。
右に要素を追加したいと思ったら、
回避する方法がないか検討することをおすすめします。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-25-natural-tail-recursion" class="outline-3">
<h3 id="2024-12-25-natural-tail-recursion">末尾再帰が自然なケース</h3>
<div class="outline-text-3" id="text-2024-12-25-natural-tail-recursion">
<p>
私はここまで末尾再帰への書き換えをしないように主張してきましたが、
末尾再帰そのものが悪いわけではありません。
</p>

<p>
処理の目的上必然的に末尾再帰になる場合も多々あり、
そのようなケースについては当然そのまま末尾再帰にするのがよいでしょう。
</p>

<p>
一例として <code>reverse-append</code> を定義してみます。
</p>

<p>
これは <code>(reverse-append x y)</code> は <code>y</code> に
<code>x</code> を反転したリストを連結する手続きです。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">reverse-append</span> lst1 lst2)
  (<span class="org-keyword">if</span> (not (pair? lst1))
      (<span class="org-keyword">if</span> (null? lst1)
          lst2
          (error <span class="org-string">"reverse-append: &#30495;&#12522;&#12473;&#12488;&#12434;&#26399;&#24453;&#12375;&#12390;&#12356;&#12414;&#12377;"</span> lst1))
      (reverse-append (cdr lst1)
                      (cons (car lst1) lst2))))
</pre>
</div>

<p>
<code>reverse-append</code> ですが、 <code>lst1</code>
が空リストの場合とそうでない場合に分けて検討してみましょう。
(<code>(not (pair? lst1))</code> かつ <code>(not (null? lst1))</code> の場合は省略)
</p>

<div class="org-src-container">
<pre class="src src-scheme">(implies (<span class="org-keyword">and</span> (not (pair lst))
              (list? lst))
         (equal? (reverse-append lst1 lst2)
                 lst2))

<span class="org-comment-delimiter">;; </span><span class="org-comment">2
</span>(implies (pair lst)
         (equal? (reverse-append lst1 lst2)
                 (reverse-append (cdr lst1)
                                 (cons (car lst1) lst2))))
</pre>
</div>

<p>
これだと1番目は計算の目的から明らかに正しいですね。
問題は2番目ですが、
これは、「 <code>lst2</code> に <code>lst1</code> のリストの先頭要素を追加したものに、
<code>lst1</code> の最初の要素を取り除いたリストを反転して連結したもの」と、
「 <code>lst2</code> に <code>lst1</code> を反転して連結したもの」が等しいと主張しています。
まあこれは正しいでしょう。
再帰手続きの説明の難しさに、
当然すぎてそれをどう説明すればいいのかよく分からないというのがありますが、
<code>reverse-append</code> もその程度には美しい定義なのです。
</p>

<p>
<code>%my-map-tail</code> のときとは何が違うのでしょうか。
再掲します。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-map-tail</span> proc lst)
  (%my-map proc lst '()))

(<span class="org-keyword">define</span> (<span class="org-function-name">%my-map-tail</span> proc lst acc)
  (<span class="org-keyword">if</span> (not (pair? lst))
      (reverse acc)
      (%my-map-tail proc
                    (cdr lst)
                    (cons (proc (car lst))
                          acc))))
</pre>
</div>

<p>
比較すると、 <code>reverse-append</code> の <code>lst2</code> は
<code>reverse-append</code> の機能に必然的に必要な変数なのに対し、
<code>%my-map-tail</code> の <code>acc</code> は <code>my-map-tail</code> の
「リスト <code>lst</code> を手続き <code>proc</code> で写したリストを求める」
という主要な機能とは何ら関係のない変数です。
つまり <code>acc</code> が手続きの機能と何ら関係ないゆえに分かりにくくなるのです。
</p>

<p>
それに対して <code>reverse-append</code> の
「 <code>lst2</code> に <code>lst1</code> を反転して連結したリストを作る」という機能には
<code>lst2</code> は必然的に必要な変数であり自然なのです。
</p>

<p>
それが <code>%my-map-tail</code> と <code>reverse-append</code> の違いであり、
末尾再帰による実装でも <code>reverse-append</code>
手続きにとって主要な意味を持っていれば自然と理解できます。
</p>

<p>
ちなみに、リストを反転する手続き <code>reverse</code> は
<code>reverse-append</code> の特別な場合だと考えられます。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-reverse</span> lst)
  (reverse-append lst '()))
</pre>
</div>
</div>
</div>
<div id="outline-container-2024-12-25-hayai-case" class="outline-3">
<h3 id="2024-12-25-hayai-case">末尾再帰にした方に効率がよいケース</h3>
<div class="outline-text-3" id="text-2024-12-25-hayai-case">
<p>
スタックオーバーフローを起こさない処理系では、
スタックがあふれそうになったタイミングでスタックを拡張するため、
ヒープ領域のメモリを確保します。
この点でメモリ使用量が大きくなるため、可読性は下がりますが末尾再帰の方がよいです。
「末尾再帰への変換をやめよう」はスタックの替わりとなる構造を、
プログラマが明示的に扱わないといけない場合についてパフォーマンス的にも正当化されます。
</p>

<p>
そのため、末尾再帰に変換する際にコールスタックを積む分について、
替わりとなるスタックを用意しなくてよいような場合は末尾再帰にした方が効率がよくなります。
</p>

<p>
以下のようにリストの長さを求める手続き
<code>my-length</code> を定義してみます。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-length</span> lst)
  (<span class="org-keyword">if</span> (not (pair? lst))
      (<span class="org-keyword">if</span> (null? lst)
          0
          (error <span class="org-string">"my-length: &#12522;&#12473;&#12488;&#12391;&#12399;&#12354;&#12426;&#12414;&#12379;&#12435;"</span> lst))
      (+ 1 (my-length (cdr lst)))))
</pre>
</div>

<p>
<code>my-length</code> を求めるのに、
<code>my-length</code> 手続きが lst の長さの分だけ呼ばれるため、
無駄にスタックに積まれていき、
無駄に <code>(+ 1 _)</code> の計算をするために戻っていかないとけません。
</p>

<p>
それに対して以下の <code>my-length-tail</code> はどうでしょうか？
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">my-length-tail</span> lst acc)
  (<span class="org-keyword">if</span> (not (pair? lst))
      (<span class="org-keyword">if</span> (null? lst)
          acc
          (error <span class="org-string">"my-length-tail: &#12522;&#12473;&#12488;&#12391;&#12399;&#12354;&#12426;&#12414;&#12379;&#12435;"</span> lst))
      (my-length-tail (cdr lst) (+ 1 acc))))
</pre>
</div>

<p>
<code>my-length-tail</code> ではスタックに積む必要もなく、戻る処理もありません。
</p>

<p>
以上により、 <code>my-length-tail</code> の方が効率的です。
</p>
</div>
</div>
<div id="outline-container-2024-12-25-saiki-hitsuyo" class="outline-3">
<h3 id="2024-12-25-saiki-hitsuyo">深い再帰がかけるのは言語機能である</h3>
<div class="outline-text-3" id="text-2024-12-25-saiki-hitsuyo">
<p>
スタックオーバーフローが起きるかどうかは
処理系に依存する問題だから避けた方がよいという
立場もあるかもしれません。
</p>

<p>
しかし、むしろ深くネストした再帰を書ける
という言語機能を提供しているかいないかと考えるべきです。
</p>

<p>
たとえば、あなたが再帰下降パーサを実装して
JSON 構文をパースするプログラムを書いているとします。
</p>

<p>
再帰手続きを使って自然に実装すると、
次のような深くネストした JSON をパースする場合に
再帰のネストも深くなるはずです。
</p>

<div class="org-src-container">
<pre class="src src-js">[[ &#8230; [[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]] &#8230;  ]]
</pre>
</div>

<p>
このようなケースで、
スタックオーバーフローの懸念がある場合には、
シンプルで美しい実装するのを諦めて、
スタックを用意して明示的に状態管理をするはめになります。
</p>

<p>
コードは無駄に複雑化し、
最初の実装よりも可読性が
大幅に低下することは避けられません。
これは再帰に課せられた本質的な制約ではありません。
言語処理系が深くネストした再帰をサポートしていない
ということが問題なのです。
</p>

<p>
末尾呼び出し最適化があるかどうかで、
プログラムの書き方を大きく変化させてしまうのと同様に、
深くネストした再帰が書けるのかどうかも、
プログラムの書き方を大幅に変えてしまうのです。
</p>

<p>
もしも、あなたが再帰を重視するのであれば、
簡単にスタックオーバーフローを引き起してしまう、
言語処理系を避けて、
シンプルな再帰手続きを書くことを推奨します。
</p>
</div>
</div>
<div id="outline-container-2024-12-25-nest-supported" class="outline-3">
<h3 id="2024-12-25-nest-supported">深くネストした再帰をサポートするScheme処理系</h3>
<div class="outline-text-3" id="text-2024-12-25-nest-supported">
</div>
<div id="outline-container-2024-12-25-kensho-hoho" class="outline-4">
<h4 id="2024-12-25-kensho-hoho">検証方法</h4>
<div class="outline-text-4" id="text-2024-12-25-kensho-hoho">
<p>
1千万回のネストでスタックオーバーフローすると仮定して、
テストして問題ないか検証しました。
</p>

<p>
下記のコードを実行して正常に返ってくるかを確認します。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">let</span> <span class="org-function-name">f</span> ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
</pre>
</div>

<p>
OS は GNU Guix System です。
検証時の <code>ulimit -s</code> の値は <code>9788</code> でした。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ ulimit -s
9788
</pre>
</div>

<p>
以下の通り、C言語のコードでは
100万回のネストでスタックオーバーフローしたため、
Scheme での検証では余裕を持って1000万回のネストに耐えられるかを検証します。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ cat sum.c 
<span class="org-comment-delimiter">#</span><span class="org-comment">include &lt;stdio.h&gt;
</span><span class="org-comment-delimiter">#</span><span class="org-comment">include &lt;stdlib.h&gt;
</span>
long long sum(long long n) {
  <span class="org-keyword">if</span> (n &lt;= 0) {
    <span class="org-keyword">return</span> 0;
  } <span class="org-keyword">else</span> {
    <span class="org-keyword">return</span> n + sum(n - 1);
  }
}

int main(int argc, char **argv) {
  long n = atol(argv[1]);
  printf(<span class="org-string">"result: %ld\n"</span>, sum(n));
  <span class="org-keyword">return</span> 0;
}
$ guix shell gcc -- gcc sum.c -o sum
$ ./sum 100000
result: 5000050000
$ ./sum 1000000
Segmentation fault
$ 
</pre>
</div>
</div>
</div>
<div id="outline-container-2024-12-25-sorezorenokensyo" class="outline-4">
<h4 id="2024-12-25-sorezorenokensyo">それぞれの処理系での検証</h4>
<div class="outline-text-4" id="text-2024-12-25-sorezorenokensyo">
<p>
検証した処理系についてですが、
2024/12/25 現在で GNU Guix
で簡単にインストールして動かすことのできた処理系に限定して調査しました。
</p>

<p>
こちらのリストは今後更新していこうと思います。
</p>
</div>
<ul class="org-ul">
<li><a id="2024-12-25-guile"></a><a href="https://www.gnu.org/software/guile/">GNU Guile</a><br />
<div class="outline-text-5" id="text-2024-12-25-guile">
<p>
GNU Guile のドキュメントの<a href="https://www.gnu.org/software/guile/manual/html_node/Stack-Overflow.html">6.26.3.4 Stack Overflow</a>
にGNU Guile にはスタックのリミットがないとの記載があります。
ドキュメントに明示的に記載があるため、
GNU Guile のこの振舞いは偶然のものではなくて、
処理系の仕様であると解釈できます。
</p>

<p>
また、 <code>call-with-stack-overflow-handler</code>
手続きを使うことで、
スタックに制限をかけてさらに、
制限にかかった場合にハンドリングすることもできます。
</p>


<p>
GNU Guile に閉じている限りは再帰のネストに制限がなく、
必要であれば制限をかけることができハンドリング可能ということで、
理想的なパターンといえます。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell guile@3 -- guile
GNU Guile 3.0.9
<span class="org-function-name">Copyright</span> (C) 1995-2023 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; <span class="org-keyword">for</span> details type <span class="org-sh-quoted-exec">`,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `</span>,show c<span class="org-string">' for details.

Enter `,help'</span> for help.
scheme@(guile-user)&gt; (let f ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
$<span class="org-variable-name">1</span> = 50000005000000
scheme@(guile-user)&gt; 
</pre>
</div>
</div>
</li>
<li><a id="2024-12-25-racket"></a><a href="https://racket-lang.org/">Racket</a><br />
<div class="outline-text-5" id="text-2024-12-25-racket">
<p>
Racket には <a href="https://docs.racket-lang.org/guide/Lists__Iteration__and_Recursion.html">2.3 Lists, Iteration, and Recursion</a> に記載があります。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell racket -- racket
Welcome to Racket v8.14 [cs].
&gt; (let f ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
50000005000000
</pre>
</div>
</div>
</li>
<li><a id="org366276c"></a><a href="https://practical-scheme.net/images/Gauche-logo.png">Gauche</a><br />
<div class="outline-text-5" id="text-org366276c">
<p>
以下の検証コードを使って、スタックオーバーフローするか確認します。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">let</span> <span class="org-function-name">f</span> ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
</pre>
</div>

<p>
スタックオーバーフローするなら、
1千万回ネストした再帰を実行すればさすがに溢れると仮定して、
検証します。
</p>

<p>
結果は以下の通りで、深いネストをサポートしています。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell gauche -- gosh -V
Gauche scheme shell, version 0.9.15 [utf-8,pthreads], x86_64-unknown-linux-gnu
(version <span class="org-string">"0.9.15"</span>)
(command <span class="org-string">"gosh"</span>)
(scheme.id gauche)
(languages scheme r5rs r7rs)
(encodings utf-8)
(website <span class="org-string">"https://practical-scheme.net/gauche"</span>)
(build.platform <span class="org-string">"x86_64-unknown-linux-gnu"</span>)
(build.configure <span class="org-string">"CONFIG_SHELL=/gnu/store/3jhfhxdf6v5ms10x5zmnl166dh3yhbr1-bash-minimal-5.1.16/bin/bash"</span> <span class="org-string">"SHELL=/gnu/store/3jhfhxdf6v5ms10x5zmnl166dh3yhbr1-bash-minimal-5.1.16/bin/bash"</span> <span class="org-string">"--prefix=/gnu/store/jawf840rbncdfrjc05fnf04lgd6bz2sm-gauche-0.9.15"</span> <span class="org-string">"--enable-fast-install"</span> <span class="org-string">"--build=x86_64-unknown-linux-gnu"</span> <span class="org-string">"--with-slib=/gnu/store/sk1c72ffl712ky8rkkm6vv0wi4jshiqz-slib-3c1/lib/slib"</span> <span class="org-string">"--with-tls=mbedtls"</span> <span class="org-string">"build_alias=x86_64-unknown-linux-gnu"</span>)
(scheme.path <span class="org-string">"/gnu/store/jawf840rbncdfrjc05fnf04lgd6bz2sm-gauche-0.9.15/share/gauche-0.98/site/lib"</span> <span class="org-string">"/gnu/store/jawf840rbncdfrjc05fnf04lgd6bz2sm-gauche-0.9.15/share/gauche-0.98/0.9.15/lib"</span>)
(threads pthreads)
(gauche.net.tls mbedtls)
$ guix shell gauche -- gosh
gosh&gt; (let f ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
50000005000000
gosh&gt; 
</pre>
</div>
</div>
</li>
<li><a id="2024-12-25-chez"></a><a href="https://www.scheme.com/index.html">Chez Scheme</a><br />
<div class="outline-text-5" id="text-2024-12-25-chez">
<p>
1000万回でもスタックオーバーフローしません。
</p>

<div class="org-src-container">
<pre class="src src-scheme">$ guix shell chez-scheme -- scheme
Chez Scheme Version 10.1.0
Copyright 1984-2024 Cisco Systems, Inc.

&gt; (<span class="org-keyword">let</span> <span class="org-function-name">f</span> ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
50000005000000
&gt; 
</pre>
</div>
</div>
</li>
<li><a id="2024-12-25-chicken"></a><a href="http://www.call-cc.org/">Chicken Scheme</a><br />
<div class="outline-text-5" id="text-2024-12-25-chicken">
<p>
Chicken Scheme ではインタプリタとコンパイラの両方を確認します。
</p>
</div>
<ul class="org-ul">
<li><a id="org3fb9514"></a>インタプリタ<br />
<div class="outline-text-6" id="text-org3fb9514">
<div class="org-src-container">
<pre class="src src-shell">$ guix shell chicken  -- csi
CHICKEN
(c) 2008-2022, The CHICKEN Team
(c) 2000-2007, Felix L. Winkelmann
Version 5.4.0 (rev 1a1d1495)
linux-unix-gnu-x86-64 [ 64bit dload ptables ]

Type ,? for help.
<span class="org-comment-delimiter">#</span><span class="org-comment">;1&gt; (let f ((i 10000000)) (if (= i 0) 0 (+ i (f (- i 1)))))
</span>50000005000000
<span class="org-comment-delimiter">#</span><span class="org-comment">;2&gt; </span>
</pre>
</div>
</div>
</li>
<li><a id="orgd11c0ff"></a>コンパイラ<br />
<div class="outline-text-6" id="text-orgd11c0ff">
<div class="org-src-container">
<pre class="src src-shell">$ cat sum.scm 
(display (let f ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1))))))
(newline)
$ guix shell chicken  -- csc sum.scm
$ ./sum 
50000005000000
$ 
</pre>
</div>
</div>
</li>
</ul>
</li>
<li><a id="2024-12-25-gambit-c"></a><a href="http://www.gambitscheme.org/">Gambit-C</a><br />
<div class="outline-text-5" id="text-2024-12-25-gambit-c">
</div>
<ul class="org-ul">
<li><a id="org1b04a0d"></a>インタプリタ<br />
<div class="outline-text-6" id="text-org1b04a0d">
<p>
私の環境だと インタプリタで 1千万で試すと、
結果が返ってこなかったのですが、一桁少ない百万であれば大丈夫でした。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell gambit-c -- gsi
Gambit v4.9.5

&gt; (let f ((i 1000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
500000500000
&gt; 
</pre>
</div>
</div>
</li>
<li><a id="orgde69de4"></a>コンパイラ<br />
<div class="outline-text-6" id="text-orgde69de4">
<p>
<code>gsc</code> でコンパイルしたところ、
1千万でも問題なく実行できました。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix show gambit-c
name: gambit-c
version: 4.9.5
outputs:
+ out: everything
systems: x86_64-linux i686-linux
dependencies: 
location: gnu/packages/scheme.scm:561:2
homepage: http://www.gambitscheme.org/
license: LGPL 2.1+, ASL 2.0
synopsis: Efficient Scheme interpreter and compiler  
description: Gambit consists of two
+ main programs: gsi, the Gambit Scheme
+ interpreter, and gsc, the Gambit Scheme
+ compiler.  The interpreter contains the
+ complete execution and debugging
+ environment.  The compiler is the
+ interpreter extended with the
+ capability of generating executable
+ files.  The compiler can produce
+ standalone executables or compiled
+ modules which can be loaded at run
+ time.  Interpreted code and compiled
+ code can be freely mixed.

$ cat sum.scm
(display (let f ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1))))))
(newline)
$ guix shell gcc gambit-c -- gsc -exe sum
$ ./sum
50000005000000
$ 
</pre>
</div>
</div>
</li>
</ul>
</li>
<li><a id="2024-12-25-chibi"></a><a href="https://github.com/ashinn/chibi-scheme">Chibi-Scheme</a><br />
<div class="outline-text-5" id="text-2024-12-25-chibi">
<p>
百万のネストでスタックオーバーフローしました。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell chibi-scheme -- chibi-scheme -V
chibi-scheme 0.11.0 <span class="org-string">"sodium"</span> (chibi chibi-0.11.0 r7rs ratios complex mini-float uvector threads full-unicode modules dynamic-loading linux x86_64 little-endian)
$ guix shell chibi-scheme -- chibi-scheme
&gt; (let f ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
ERROR: out of stack space
&gt; (let f ((i 1000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
ERROR: out of stack space
&gt; (let f ((i 100000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
5000050000
&gt; 
</pre>
</div>
</div>
</li>
<li><a id="2024-12-25-bigloo"></a><a href="https://www-sop.inria.fr/indes/fp/Bigloo/">Bigloo</a><br />
<div class="outline-text-5" id="text-2024-12-25-bigloo">
<p>
セメンテーション違反が発生してエラーとなりました。
(出力にメールアドレスが含まれていたため <code>@</code> を空白に置換しました)
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell bigloo -- bigloo
------------------------------------------------------------------------------
<span class="org-function-name">Bigloo</span> (4.3g)                                                            ,--^, 
<span class="org-sh-quoted-exec">`a practical Scheme compiler'                                      _ ___/ /|/  
Thu 27 Feb 2020 07:59:49 AM CET                                ,;'( )__, ) '   
Inria -- Sophia Antipolis                                     ;;  //   L__.    
email: bigloo lists-sop.inria.fr                              '   \    /  '    
url: http://www-sop.inria.fr/indes/fp/Bigloo                       ^   ^       
------------------------------------------------------------------------------


1:=&gt; (let f ((i 10000000)) (if (= i 0) 0 (+ i (f (- i 1)))))
*** ERROR:bigloo:
`</span>segmentation violation<span class="org-string">' exception -- raised
    1. \@f toplevel, stdin:1
    2. \@f toplevel, stdin:1
    3. \@f toplevel, stdin:1
    4. \@f toplevel, stdin:1
    5. \@f toplevel, stdin:1
    6. \@f toplevel, stdin:1
    7. \@f toplevel, stdin:1
    8. \@f toplevel, stdin:1
    9. \@f toplevel, stdin:1
   10. \@f toplevel, stdin:1
1:=&gt; (let f ((i 1000000)) (if (= i 0) 0 (+ i (f (- i 1)))))
*** ERROR:bigloo:
`segmentation violation'</span> exception -- raised
    1. <span class="org-string">\@</span>f toplevel, stdin:2
    2. <span class="org-string">\@</span>f toplevel, stdin:2
    3. <span class="org-string">\@</span>f toplevel, stdin:2
    4. <span class="org-string">\@</span>f toplevel, stdin:2
    5. <span class="org-string">\@</span>f toplevel, stdin:2
    6. <span class="org-string">\@</span>f toplevel, stdin:2
    7. <span class="org-string">\@</span>f toplevel, stdin:2
    8. <span class="org-string">\@</span>f toplevel, stdin:2
    9. <span class="org-string">\@</span>f toplevel, stdin:2
   10. <span class="org-string">\@</span>f toplevel, stdin:2
1:=&gt; (let f ((i 100000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
*** ERROR:bigloo:
<span class="org-sh-quoted-exec">`segmentation violation' exception -- raised
    1. \@f toplevel, stdin:3
    2. \@f toplevel, stdin:3
    3. \@f toplevel, stdin:3
    4. \@f toplevel, stdin:3
    5. \@f toplevel, stdin:3
    6. \@f toplevel, stdin:3
    7. \@f toplevel, stdin:3
    8. \@f toplevel, stdin:3
    9. \@f toplevel, stdin:3
   10. \@f toplevel, stdin:3
1:=&gt; (let f ((i 10000)) (if (= i 0) 0 (+ i (f (- i 1)))))
50005000
1:=&gt; </span>
</pre>
</div>
</div>
</li>
<li><a id="2024-12-25-mit-scheme"></a><a href="https://www.gnu.org/software/mit-scheme/">MIT-Sceheme</a><br />
<div class="outline-text-5" id="text-2024-12-25-mit-scheme">
<p>
最大の再帰の深さを越えたとエラーになりました。
10万なら大丈夫のようです。
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell mit-scheme -- mit-scheme
MIT/GNU Scheme running under GNU/Linux
Type <span class="org-sh-quoted-exec">`^C' (control-C) followed by `</span>H<span class="org-string">' to obtain information about interrupts.

Copyright (C) 2020 Massachusetts
    Institute of Technology
This is free software; see the
source for copying conditions. There
is NO warranty; not even for
MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

Image saved on Sunday March 7, 2021 at 3:24:56 PM
  Release 11.2 || SF || LIAR/x86-64

1 ]=&gt; (let f ((i 10000000)) (if (= i 0) 0 (+ i (f (- i 1)))))

;Aborting!: maximum recursion depth exceeded

1 ]=&gt; (let f ((i 1000000)) (if (= i 0) 0 (+ i (f (- i 1)))))

;Aborting!: maximum recursion depth exceeded

1 ]=&gt; (let f ((i 100000)) (if (= i 0) 0 (+ i (f (- i 1)))))

;Value: 5000050000

1 ]=&gt; </span>
</pre>
</div>
</div>
</li>
<li><a id="2024-12-25-scheme48"></a><a href="https://s48.org/">Scheme48</a><br />
<div class="outline-text-5" id="text-2024-12-25-scheme48">
<p>
1000万だとエラーになりました。
10万なら大丈夫のようです。
(出力にメールアドレスが含まれていたため <code>@</code> を空白に置換しました)
</p>


<div class="org-src-container">
<pre class="src src-shell">$ guix shell scheme48 -- scheme48
Welcome to Scheme 48 1.9.2 (made by *GOK* on 2024-06-18)
See http://s48.org/ for more information.
Please report bugs to scheme-48-bugs s48.org.
Get more information at http://www.s48.org/.
Type ,? (comma question-mark) <span class="org-keyword">for</span> help.
&gt; (let f ((i 10000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
gc: Scheme 48 heap overflow (max heap size 4000000 cells)

$ guix shell scheme48 -- scheme48
Welcome to Scheme 48 1.9.2 (made by *GOK* on 2024-06-18)
See http://s48.org/ for more information.
Please report bugs to scheme-48-bugs s48.org.
Get more information at http://www.s48.org/.
Type ,? (comma question-mark) <span class="org-keyword">for</span> help.
&gt; (let f ((i 10000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
50005000
&gt; (let f ((i 100000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
5000050000
&gt; (let f ((i 1000000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
gc: Scheme 48 heap overflow (max heap size 4000000 cells)

</pre>
</div>
</div>
</li>
<li><a id="2024-12-25-stklos"></a><a href="https://stklos.net">STklos</a><br />
<div class="outline-text-5" id="text-2024-12-25-stklos">
<p>
スタックサイズは固定のようですが、
起動時のオプションで拡張できるようです。
</p>

<p>
デフォルトで問題がありそうなので、
末尾再帰への変換が不要とはいえなそうです。
(出力にメールアドレスが含まれていたため <code>@</code> を空白に置換しました)
</p>

<div class="org-src-container">
<pre class="src src-shell">$ guix shell stklos -- stklos
  <span class="org-string">\ </span>   STklos version 2.10 (stable)
   <span class="org-string">\ </span>  Copyright (C) 1999-2024 Erick Gallesio &lt;eg stklos.net&gt;
  / <span class="org-string">\ </span> [Linux-6.10.14-gnu-x86_64/pthreads/readline/utf8]
 /   <span class="org-string">\ </span>Type <span class="org-string">',h'</span> for help
stklos&gt; (let f ((i 100000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
Received a SIGSEGV signal.
Try to augment stack size (--stack-size option). If the problem persists,
fill an issue report on https://github.com/egallesio/STklos/issues
$ guix shell stklos -- stklos --stack-size=10000000
  <span class="org-string">\ </span>   STklos version 2.10 (stable)
   <span class="org-string">\ </span>  Copyright (C) 1999-2024 Erick Gallesio &lt;eg stklos.net&gt;
  / <span class="org-string">\ </span> [Linux-6.10.14-gnu-x86_64/pthreads/readline/utf8]
 /   <span class="org-string">\ </span>Type <span class="org-string">',h'</span> for help
stklos&gt; (let f ((i 100000)) (<span class="org-keyword">if</span> (= i 0) 0 (+ i (f (- i 1)))))
5000050000
stklos&gt; 
</pre>
</div>
</div>
</li>
</ul>
</div>
<div id="outline-container-2024-12-25-kensyo-matome" class="outline-4">
<h4 id="2024-12-25-kensyo-matome">検証結果のまとめ</h4>
<div class="outline-text-4" id="text-2024-12-25-kensyo-matome">
<p>
それぞれの検証結果としては以下のようになりました。
スタックオーバーフローしないものについて、
ドキュメントでの記載があるか調べたのですが、
私が調査した限り見つけられなかったものは「不明」としています。
</p>

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-left" />
</colgroup>

<colgroup>
<col  class="org-left" />
</colgroup>

<colgroup>
<col  class="org-left" />
</colgroup>

<colgroup>
<col  class="org-left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">言語処理系</th>
<th scope="col" class="org-left">1000万ネストした再帰</th>
<th scope="col" class="org-left">ドキュメント</th>
<th scope="col" class="org-left">備考</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">GNU Guile</td>
<td class="org-left">可能</td>
<td class="org-left"><a href="https://www.gnu.org/software/guile/manual/html_node/Stack-Overflow.html">記載あり</a></td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Racket</td>
<td class="org-left">可能</td>
<td class="org-left"><a href="https://docs.racket-lang.org/guide/Lists__Iteration__and_Recursion.html">記載あり</a></td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Gauche</td>
<td class="org-left">可能</td>
<td class="org-left">不明</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Chez Scheme</td>
<td class="org-left">可能</td>
<td class="org-left">不明</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Chicken Scheme</td>
<td class="org-left">可能</td>
<td class="org-left">不明</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Gambit-C</td>
<td class="org-left">可能</td>
<td class="org-left">不明</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Chibi Scheme</td>
<td class="org-left">不可</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Bigloo</td>
<td class="org-left">不可</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">MIT-Scheme</td>
<td class="org-left">不可</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">Scheme48</td>
<td class="org-left">不可</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">STklos</td>
<td class="org-left">不可</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">起動時のオプションでスタックサイズを設定可能</td>
</tr>
</tbody>
</table>

<p>
以上から、Scheme では深くネストしても
スタックオーバーフローしない処理系が多くあることを確認できました。
</p>

<p>
ドキュメントでの記載が確認できている状態であれば、
気にすることなく再帰手続きで実装しても問題なさそうです。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-25-owarini" class="outline-3">
<h3 id="2024-12-25-owarini">おわりに</h3>
<div class="outline-text-3" id="text-2024-12-25-owarini">
<p>
再帰でスタックオーバーフローが起きるということを、
当然の前提として受け入れる必要はなく、
深くネストした再帰をサポートした処理系であれば、
「末尾再帰への変換」をせずにそのままの
美しさを保つことができます。
</p>

<p>
末尾再帰への変換には宣言的な記述を損なう弊害があり、
そのままの再帰の形を維持することの価値が伝わっていれば幸いです。
</p>
</div>
</div>
<div id="outline-container-2024-12-26-henkorireki" class="outline-3">
<h3 id="2024-12-26-henkorireki">変更履歴</h3>
<div class="outline-text-3" id="text-2024-12-26-henkorireki">
<ul class="org-ul">
<li><span class="timestamp-wrapper"><span class="timestamp">&lt;2025-02-05 水&gt; </span></span> タイトルを『「末尾再帰への書き換え」をやめよう！』から『「末尾再帰への書き換え」の弊害について』に変更。強く主張しすぎたと深く後悔したため。</li>
<li><span class="timestamp-wrapper"><span class="timestamp">&lt;2024-12-26 木&gt; </span></span> 4章と7章でベンチマークをとって実行時間を測定して比較した計測結果を載せていたのですが削除しました。計測結果の評価の時点でGCの時間も含めて評価していたのと、GCの時間からメモリの使用量を推定する解釈の誤りがあり、これらを正して再評価しようとしたところ、結果をどう評価するのが適切なのかが難しく手に負えなかったため、セクション自体を削除しました。少なくとも Guile では 末尾再帰版の <code>my-map-tail</code> で最後の <code>reverse</code> をするとGC時間が増加してしまい結果的に実行時間が長くなるという事象は条件を変えても発生し、 <code>cons</code> のコストが実行時間に影響を与えるとはいえそうなのですが、これと <code>my-map</code> がスタックを多く消費している場合に実行時間に与える影響について公平に比較するのは難しく諦めました。拡張されたスタックが使い回されるために <code>my-map</code> を繰り返すベンチマークはそもそも <code>my-map</code> が有利になるという問題もありそうです。
以上から、 <code>my-map</code> と <code>my-map-tail</code> については理屈上は時間計算量、空間計算量に大きな差はない(はず)と主張するだけに留めることにしました。</li>
<li><span class="timestamp-wrapper"><span class="timestamp">&lt;2024-12-26 木&gt; </span></span> 8章の例示が深くネストしたJSON配列の例示が深くネストしていることを適切に表現できていなかったのを修正しました。</li>
<li><span class="timestamp-wrapper"><span class="timestamp">&lt;2024-12-26 木&gt; </span></span> 7章の末尾再帰にした方が効率がよいケースで、実行時間をみて「わずか」にと記載していたのですが、空間計算量を考慮するとわずかとはいえない程度の計算量の差があるので修正しました。</li>
</ul>
</div>
</div>
]]></description>
</item>
<item>
<title>Emacsで個人サイト制作</title>
<link>https://www.tojo.tokyo/posts/create-website-with-emacs.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/create-website-with-emacs.html</guid>
<pubDate>Tue, 24 Dec 2024 00:00:00 +0000</pubDate>
<category><![CDATA[Web]]></category>
<category><![CDATA[Emacs]]></category>
<description><![CDATA[<div id="outline-container-2024-12-24-hajimeni" class="outline-3">
<h3 id="2024-12-24-hajimeni">はじめに</h3>
<div class="outline-text-3" id="text-2024-12-24-hajimeni">
<p>
<a href="https://adventar.org/calendars/10172">個人ホームページ訪問 Advent Calendar 2024</a>
の24日目の記事です。
</p>

<p>
この記事ではこのサイトをどのように作成し、
運用しているのかについて紹介します。
</p>

<p>
このサイトのコンテンツである HTML は
Emacs を使って生成しているので、
主に Emacs で Web サイト生成をする方法について解説します。
</p>

<p>
なお本記事で記載している Emacs Lisp のコードのライセンスは <code>GPL 3+</code> です。
</p>
</div>
</div>
<div id="outline-container-2024-12-24-zentei" class="outline-3">
<h3 id="2024-12-24-zentei">前提: Emacs と org-mode とは</h3>
<div class="outline-text-3" id="text-2024-12-24-zentei">
</div>
<div id="outline-container-2024-12-24-emacs-towa" class="outline-4">
<h4 id="2024-12-24-emacs-towa">Emacs とは</h4>
<div class="outline-text-4" id="text-2024-12-24-emacs-towa">
<p>
<a href="https://www.gnu.org/software/emacs/">Emacs</a> とは拡張性とカスタマイズ性に
優れた<a href="https://www.gnu.org/philosophy/free-sw.ja.html">自由</a>なテキストエディターです。
</p>

<p>
私は日常でも仕事でも常に Emacs を使っており、
メモ、日記、プログラミング、コンピュータの設定管理、タスク管理、
テキスト Web ブランジング、メール、RSS の購読、
カレンダー管理、表計算、お金の管理など
さまざまなことのために Emacs を利用しています。
</p>

<p>
そして、もちろん Web サイトの作成も Emacs でしているので、
その方法について説明します。
</p>
</div>
</div>
<div id="outline-container-2024-12-24-org-mode-towa" class="outline-4">
<h4 id="2024-12-24-org-mode-towa">Emacs の org-mode とは</h4>
<div class="outline-text-4" id="text-2024-12-24-org-mode-towa">
<p>
Emacs の <a href="https://orgmode.org/">org-mode</a> は 
org という Emacs で扱えるテキストファイルの文書フォーマットを扱うモードのことで、
文書作成、メモ作成、タスク管理、スケジュール管理、リンク管理、表計算、
文書内でのコード実行など、これまたいろんなことができます。
</p>

<p>
Emacs には org 形式の文書を html に変換して export する機能があるので、
この機能を活用して HTML を生成します。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-24-history" class="outline-3">
<h3 id="2024-12-24-history">経緯</h3>
<div class="outline-text-3" id="text-2024-12-24-history">
</div>
<div id="outline-container-2024-12-20-use-haunt" class="outline-4">
<h4 id="2024-12-20-use-haunt">Haunt 時代</h4>
<div class="outline-text-4" id="text-2024-12-20-use-haunt">
<p>
最初の投稿は 2022/02/18 (火)の<a href="https://www.tojo.tokyo/posts/hello-world.html">こんにちは、世界!</a> という記事です。
この投稿で紹介しているように初期は GNU Guile 製の
<a href="https://dthompson.us/projects/haunt.html">Haunt</a> という静的サイトジェネレータを使用していました。
当時は Web 記事を GitLab で管理をしていて、
<a href="https://gitlab.com/tojoqk/www-tojo-tokyo">www-tojo-tokyo</a> というリポジトリで管理していました。
サイトにこなくてもリポジトリの posts
ファイルの中身を見れば記事が読めるという状況になっていたようです。
</p>

<p>
Haunt は大変優れた静的サイトジェネレータです。
Haunt では公式では Texinfo, Skribe, CommonMark
の形式をサポートしているのですが、
<a href="https://files.dthompson.us/docs/haunt/latest/Reader.html">Reader</a> を追加することで新しい形式を追加することができます。
私は <a href="https://orgmode.org/ja/">org-mode</a> の形式を <a href="https://pandoc.org/">pandoc</a> で変換する方法追加していました(<a href="https://gitlab.com/tojoqk/www-tojo-tokyo/-/blob/a42c94182322dd0d9fa6ed3d9ed6cdb96aeaf90d/www-tojo-tokyo/reader/org.scm">実装</a>)
</p>
</div>
</div>
<div id="outline-container-2024-12-24-html-generation-with-emacs" class="outline-4">
<h4 id="2024-12-24-html-generation-with-emacs">Emacs で HTML の生成をしたい</h4>
<div class="outline-text-4" id="text-2024-12-24-html-generation-with-emacs">
<p>
最初は pandoc での変換結果に満足していたのですが、
後に Emacs の <a href="https://orgmode.org/manual/HTML-Export.html">HTML Export</a> 機能で出力される HTML と、
pandoc で生成される HTML の違いに不満を抱くようになりました。
まず Emacs にはソースコードに色を付ける機能が内包されているのですが、
pandoc で HTML に変換すると Emacs が付けていた色の情報は失なってしまいます。
Emacs の機能で HTML エクスポートをすれば適切に色を付けてくれるのでその機能を使いたいと思うわけです。
</p>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">ソースコード1: </span>色付けの例</label><pre class="src src-scheme">(<span class="org-keyword">define</span> (<span class="org-function-name">factorial</span> n)
  (<span class="org-keyword">if</span> (&lt;= n 0)
      1
      (* n (factorial (- n 1)))))
</pre>
</div>

<p>
また、 org-babel という機能で文書内のソースコードを実行して、実行結果を文書に含めてくれる機能があるのですが、
エクスポートしたHTMLにコードを含めるのか実行結果を含めるのかを制御する機能があったり、
HTMLのHEADに追加特定のHTMLタグを追加することができたりと、EmacsでHTMLを出力した方が便利なところがたくさんあるのです。
</p>

<p>
Emacs のエクスポート機能を使うのであれば、
Haunt に依存しなくても Emacs の機能のみを使えばいいのではないかと思うようになりました。
</p>
</div>
</div>
<div id="outline-container-2024-12-24-use-emacs" class="outline-4">
<h4 id="2024-12-24-use-emacs">Emacs で HTML 生成するように変更</h4>
<div class="outline-text-4" id="text-2024-12-24-use-emacs">
<p>
そのため、2022/03/04(金)の<a href="https://www.tojo.tokyo/posts/renewal.html"> Web サイトをリニューアルしました</a> にて、
静的サイトジェネレータを Haunt から <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a> に変更しました。
</p>

<p>
このときのリニューアルでは Haunt 時代から不便になった部分も多くあったので、
2022/11/19(土) の<a href="https://www.tojo.tokyo/posts/renewal-web-20221.html">Web サイトをリニューアルしてタグを追加した</a> のリニューアルで仕組みを大幅に改善しています。
</p>

<p>
この記事では 2022/11/19(土)以降の私のサイトの仕組みについて紹介します。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-24-blog-towa" class="outline-3">
<h3 id="2024-12-24-blog-towa">ブログ形式の Web サイトに必要なページ</h3>
<div class="outline-text-3" id="text-2024-12-24-blog-towa">
<p>
まず、
ブログ形式のホームページに必要な構成要素について考えてみましょう。
</p>

<p>
ブログで必要なページは究極的には以下の二つのみです。
</p>

<dl class="org-dl">
<dt>index.html</dt><dd>記事の一覧ページ</dd>
<dt>posts/&lt;filename&gt;.html</dt><dd>記事の詳細ページ</dd>
</dl>

<p>
ブログを公開するには究極的には上記二種類の HTML を作成して配置をすればよいということになります。
</p>

<p>
もちろん、HTML を直接配置しても問題ないでしょう。
しかし、私は HTML ではなくて org-mode で文書作成したいので、
org-mode で書いたものを自動的に HTML に変換して配置する仕組みが必要になるのです。
</p>
</div>
</div>
<div id="outline-container-2024-12-24-org-publish" class="outline-3">
<h3 id="2024-12-24-org-publish"><code>org-publish</code> で「出版」する</h3>
<div class="outline-text-3" id="text-2024-12-24-org-publish">
<p>
org-mode には <a href="https://orgmode.org/manual/Publishing.html">org-publish</a> という機能があります。
これは、org などの文書形式のファイルや css や js などを
公開用の形式(HTMLなど)に変換し、
指定したディレクトリに配置し、
そのまま公開できる状態にするものです。
</p>

<p>
例えば以下のようなディレクトリ構造で、
サイトを作成したとします。
</p>

<pre class="example" id="orgc40719f">
.
├── index.org
├── posts
│   ├── article1.org
│   ├── article2.org
│   └── article3.org
├── publish.el
└── static
    ├── css
    │   └── base.css
    └── js
        └── test.js
</pre>

<p>
次に Emacs Lisp で次のようにプログラムを書きます。
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">require</span> '<span class="org-constant">org</span>)

(<span class="org-keyword">defun</span> <span class="org-function-name">publish-www</span> ()
  (<span class="org-keyword">let*</span> ((org-html-htmlize-output-type 'css)
         (org-html-head-include-default-style nil)
         (base-directory <span class="org-string">"."</span>)
         (publishing-directory <span class="org-string">"./site"</span>)
         (org-publish-project-alist
          `((<span class="org-string">"www"</span>
             <span class="org-builtin">:language</span> <span class="org-string">"ja"</span>
             <span class="org-builtin">:base-directory</span> ,(concat base-directory)
             <span class="org-builtin">:base-extension</span> <span class="org-string">"org"</span>
             <span class="org-builtin">:recursive</span> t
             <span class="org-builtin">:exclude</span> <span class="org-string">"posts.org"</span>
             <span class="org-builtin">:publishing-directory</span> ,publishing-directory
             <span class="org-builtin">:publishing-function</span> org-html-publish-to-html
             <span class="org-builtin">:html-doctype</span> <span class="org-string">"html5"</span>)
            (<span class="org-string">"www-static"</span>
             <span class="org-builtin">:language</span> <span class="org-string">"ja"</span>
             <span class="org-builtin">:base-directory</span> ,(concat base-directory <span class="org-string">"/static"</span>)
             <span class="org-builtin">:base-extension</span> <span class="org-string">"css</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">js"</span>
             <span class="org-builtin">:recursive</span> t
             <span class="org-builtin">:html-doctype</span> <span class="org-string">"html5"</span>
             <span class="org-builtin">:publishing-directory</span> ,(concat publishing-directory <span class="org-string">"/static"</span>)
             <span class="org-builtin">:publishing-function</span> org-publish-attachment))))
    (org-publish-project <span class="org-string">"www"</span> t)
    (org-publish-project <span class="org-string">"www-static"</span> t)))
</pre>
</div>

<p>
これを以下のように実行すると…
</p>

<div class="org-src-container">
<pre class="src src-shell">emacs --batch -l publish.el -f publish-www
</pre>
</div>

<p>
<code>site</code> というディレクトリが作成されていて、
次のようにサイトで公開可能な状態にできるわけです。
</p>

<pre class="example" id="org40bb705">
site
├── index.html
├── posts
│   ├── article1.html
│   ├── article2.html
│   └── article3.html
└── static
    ├── css
    │   └── base.css
    └── js
        └── test.js
</pre>

<p>
これを Web サーバーに配置すれば、デプロイが完了です。
</p>
</div>
</div>
<div id="outline-container-2024-12-24-automation" class="outline-3">
<h3 id="2024-12-24-automation">一覧ページの記述と詳細記事の配置を自動化したい</h3>
<div class="outline-text-3" id="text-2024-12-24-automation">
<p>
しかし、たいへん怠惰な私はこれでは満足できません。
</p>

<p>
この方法でも問題なく org
文書でブログを作成することはできるのですが、
以下二点の問題があります。
</p>
</div>
<div id="outline-container-2024-12-21-automation-1" class="outline-4">
<h4 id="2024-12-21-automation-1">記事を作成するたびにファイルを作成する必要がある</h4>
<div class="outline-text-4" id="text-2024-12-21-automation-1">
<p>
この程度のことができない人にはもはや何もできないのではないかという疑いが発生しますが、
ファイルを作成するというのは意外と簡単ではありません。
ファイルを作成にするには以下の作業が必要です。
</p>

<ul class="org-ul">
<li>ファイル名を決めないといけない
<ul class="org-ul">
<li>ファイル名はパーマリンクになるので真面目に考えることになります</li>
<li>変更したい場合、ファイル名を変更しないといけない</li>
</ul></li>
<li>前の記事を確認するのに別のファイルを開かないといけない
<ul class="org-ul">
<li>前例踏襲をしたいときに困る</li>
<li>posts/ 以下のファイルを選択しなければならない
<ul class="org-ul">
<li>直近の記事を参考にしたいが、どれが直近だか分からない</li>
</ul></li>
</ul></li>
</ul>

<p>
このように posts 以下にファイルを新規作成するのは面倒なのです。
</p>
</div>
</div>
<div id="outline-container-2024-12-21-automation-2" class="outline-4">
<h4 id="2024-12-21-automation-2">一覧ページを手書きしたくない</h4>
<div class="outline-text-4" id="text-2024-12-21-automation-2">
<p>
記事を書いたら、一覧ページに記事へのリンクを張らなければなりません。
これもまた面倒な作業ですし、リンクを間違える可能性もあります。
</p>

<p>
Emacs の org-html-export では、
相対リンクを書いたときに、
リンクが先ファイルがない場合はエラーとなり失敗してくれるという機能があります。
そのため、間違えて 404 Not Found になってしまうリンクを書いてしまうリスクはないのですが、
それでも過去記事からコピペして変更せずに過去記事にリンクを張ってしまうというリスクが残ります。
</p>

<p>
直感的にもこの作業が本質的にやらないといけないことだとは思えません。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-24-ideal-format" class="outline-3">
<h3 id="2024-12-24-ideal-format">理想の形式</h3>
<div class="outline-text-3" id="text-2024-12-24-ideal-format">
<p>
では、どうすればよいでしょうか？
前述した課題を解決するには次の方法で記事をかけるとよいです。
</p>

<p>
<code>posts.org</code> という名前のファイルを一つだけ作成し、
以下形式で全ての記事を含めてしまえばよいのです。
</p>

<div class="org-src-container">
<pre class="src src-org"><span class="org-org-document-info-keyword">#+TITLE:</span> <span class="org-org-document-title">&#31169;&#12398;Web&#12469;&#12452;&#12488;
</span>
<span class="org-org-level-1">* &#35352;&#20107;3</span>
<span class="org-org-drawer">:PROPERTIES:</span>
<span class="org-org-special-keyword">:FILENAME:</span> <span class="org-org-property-value">article3</span>
<span class="org-org-special-keyword">:PUBDATE:</span> <span class="org-org-property-value"><span class="org-org-date">&lt;2024-12-23 &#26376; 00:00&gt;</span></span>
<span class="org-org-special-keyword">:DESCRIPTION:</span> <span class="org-org-property-value">&#12415;&#12387;&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12377;</span>
<span class="org-org-drawer">:END:</span>

<span class="org-org-level-2">** &#12399;&#12376;&#12417;&#12395;</span>

&#12371;&#12398;&#35352;&#20107;&#12399;3&#12388;&#12417;&#12391;&#12377;

<span class="org-org-level-2">** &#12362;&#12431;&#12426;&#12395;</span>

3&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12375;&#12383;

<span class="org-org-level-1">* &#35352;&#20107;2</span>
<span class="org-org-drawer">:PROPERTIES:</span>
<span class="org-org-special-keyword">:FILENAME:</span> <span class="org-org-property-value">article2</span>
<span class="org-org-special-keyword">:PUBDATE:</span> <span class="org-org-property-value"><span class="org-org-date">&lt;2024-12-22 &#26085; 00:00&gt;</span></span>
<span class="org-org-special-keyword">:DESCRIPTION:</span> <span class="org-org-property-value">&#12405;&#12383;&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12377;</span>
<span class="org-org-drawer">:END:</span>

<span class="org-org-level-2">** &#12399;&#12376;&#12417;&#12395;</span>

&#12371;&#12398;&#35352;&#20107;&#12399;2&#12388;&#12417;&#12391;&#12377;

<span class="org-org-level-2">** &#12362;&#12431;&#12426;&#12395;</span>

2&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12375;&#12383;


<span class="org-org-level-1">* &#35352;&#20107;1</span>
<span class="org-org-drawer">:PROPERTIES:</span>
<span class="org-org-special-keyword">:FILENAME:</span> <span class="org-org-property-value">article1</span>
<span class="org-org-special-keyword">:PUBDATE:</span> <span class="org-org-property-value"><span class="org-org-date">&lt;2024-12-21 Fri 00:00&gt;</span></span>
<span class="org-org-special-keyword">:DESCRIPTION:</span> <span class="org-org-property-value">&#12402;&#12392;&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12377;</span>
<span class="org-org-drawer">:END:</span>

<span class="org-org-level-2">** &#12399;&#12376;&#12417;&#12395;</span>

&#12371;&#12398;&#35352;&#20107;&#12399;1&#12388;&#12417;&#12391;&#12377;

<span class="org-org-level-2">** &#12362;&#12431;&#12426;&#12395;</span>

1&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12375;&#12383;
</pre>
</div>

<p>
このファイルを解析して、
次のような構成でファイルを置くスクリプトを書けば問題が解決するわけです。
</p>

<pre class="example" id="orge2519ed">
.
├── index.org
└── posts
     ├── article1.org
     ├── article2.org
     └── article3.org
</pre>
</div>
<div id="outline-container-2024-12-21-new-article-with-org-capture" class="outline-4">
<h4 id="2024-12-21-new-article-with-org-capture"><code>org-capture</code> で記事を新規作成する</h4>
<div class="outline-text-4" id="text-2024-12-21-new-article-with-org-capture">
<p>
しかし、スクリプトうんぬんの前にこの形式の posts.org を書くこと自体が面倒くさいのではないか？という問いがあります。
この問題は Emacs の org-mode の、 <code>org-capture</code> という機能を使うことで解決します。
</p>

<p>
Emacs に以下のような設定をします。
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(global-set-key (kbd <span class="org-string">"C-c c"</span>) 'org-capture)

(<span class="org-keyword">setq</span> org-capture-templates
      `((<span class="org-string">"w"</span> <span class="org-string">"&#26032;&#12375;&#12356;&#35352;&#20107;"</span> entry (file <span class="org-string">"~/www/posts.org"</span>)
         <span class="org-string">"* %^{TITLE}
:PROPERTIES:
:FILENAME: %^{ID}
:PUBDATE: %^T
:DESCRIPTION: %^{DESCRIPTION}
:END:

%?"</span>
         <span class="org-builtin">:prepend</span> t
         <span class="org-builtin">:jump-to-captured</span> t)))
</pre>
</div>

<p>
この設定を反映した後に <code>C-c c</code>  (Controlを押しながらcを押した後に単独で c を押す)と、
<code>org-capture</code> で記事を新規作成できます。
</p>


<div id="org7ef4c31" class="figure">
<p><img src="https://files.tojo.tokyo/www/create-website-with-emacs/demo.gif" alt="demo.gif" />
</p>
<p><span class="figure-number">&#22259;1:  </span>org-capture で記事を新規作成するデモ</p>
</div>
</div>
</div>
</div>
<div id="outline-container-2024-12-21-emacs-static-website-generator" class="outline-3">
<h3 id="2024-12-21-emacs-static-website-generator">Emacs を静的サイト生成器に</h3>
<div class="outline-text-3" id="text-2024-12-21-emacs-static-website-generator">
<p>
さて、 <code>posts.org</code> から <code>index.org</code> と <code>posts/&lt;filename&gt;.org</code>
を生成するにはどうしたらよいでしょうか？
org 形式はテキストフォーマットではあるのですが、
結構複雑な形式です。
これを解析するのには少し手間がかかります。
</p>

<p>
しかし、実は私は org 形式の解析器を既に手にしています。
そう Emacs です。Emacs はテキストエディタですが、
その高い拡張性から Emacs をorg形式を解析して、
必要なorgファイルを作成するツールとしても使うことができるのです。
</p>
</div>
<div id="outline-container-2024-12-21-posts-to-index" class="outline-4">
<h4 id="2024-12-21-posts-to-index"><code>posts.org</code> から <code>index.org</code> を作成する</h4>
<div class="outline-text-4" id="text-2024-12-21-posts-to-index">
<p>
次のようなスクリプトを作成します。
</p>

<p>
なお、実際の私のサイトはタグ機能などをサポートしていて、複雑になっているため簡略化しています。
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="org-comment-delimiter">;; </span><span class="org-comment">&#31777;&#21336;&#12395; html-escape &#12377;&#12427;
</span>(<span class="org-keyword">defun</span> <span class="org-function-name">html-escape</span> (str)
  (<span class="org-keyword">let*</span> ((str (string-replace <span class="org-string">"&amp;"</span> <span class="org-string">"&amp;amp;"</span> str))
         (str (string-replace <span class="org-string">"&lt;"</span> <span class="org-string">"&amp;lt;"</span> str))
         (str (string-replace <span class="org-string">"&gt;"</span> <span class="org-string">"&amp;gt;"</span> str))
         (str (string-replace <span class="org-string">"\""</span> <span class="org-string">"&amp;quot;"</span> str)))
    str))

(<span class="org-keyword">defun</span> <span class="org-function-name">find-index-file</span> ()
  (<span class="org-keyword">let</span> ((description <span class="org-string">"&#31169;&#12398; Web &#12469;&#12452;&#12488; &amp;&amp;&amp; &#12487;&#12514; &amp;&amp;&amp;"</span>))
    (<span class="org-keyword">cond</span> ((not (file-exists-p *path*))
           <span class="org-comment-delimiter">;; </span><span class="org-comment">&#21021;&#22238;&#12399; index.org &#12398;&#26368;&#21021;&#12398;&#37096;&#20998;&#12434;&#20316;&#25104;&#12377;&#12427;
</span>           (find-file *path*)
           (insert <span class="org-string">"#+TITLE: &#31169;&#12398;Web&#12469;&#12452;&#12488;!\n"</span>
                   <span class="org-string">"#+HTML_HEAD: &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/&gt;\n"</span>
                   <span class="org-string">"#+HTML_HEAD: &lt;link rel=\"stylesheet\" href=\"/static/css/base.css\"/&gt;\n"</span>
                   <span class="org-string">"#+OPTIONS: email:nil num:nil toc:nil\n"</span>)
           (insert (format <span class="org-string">"#+DESCRIPTION: %s\n"</span> (html-escape description))))
          (t (find-file *path*)))))

<span class="org-comment-delimiter">;; </span><span class="org-comment">&#26178;&#21051;&#12363;&#12425;&#26085;&#20184;&#12434;&#21462;&#12426;&#20986;&#12377;
</span>(<span class="org-keyword">defun</span> <span class="org-function-name">strip-time</span> (pubdate)
  (concat (substring pubdate 0 -7)<span class="org-string">"&gt;"</span>))

(<span class="org-keyword">defvar</span> <span class="org-variable-name">*path*</span> <span class="org-string">"./index.org"</span>)

<span class="org-comment-delimiter">;; </span><span class="org-comment">posts.org &#12434;&#38283;&#12367;
</span>(find-file <span class="org-string">"posts.org"</span>)

(<span class="org-keyword">let</span> ((pt nil))         <span class="org-comment-delimiter">; </span><span class="org-comment">pt &#12399;&#12459;&#12540;&#12477;&#12523;&#12398;&#20301;&#32622;&#12434;&#35352;&#37682;&#12375;&#12390;&#12362;&#12367;&#12383;&#12417;&#12398;&#22793;&#25968;
</span>  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12501;&#12449;&#12452;&#12523;&#12398;&#26368;&#23567;&#12398; heading &#12414;&#12391;&#12459;&#12540;&#12477;&#12523;&#12434;&#31227;&#21205;
</span>  (org-next-visible-heading 1)
  <span class="org-comment-delimiter">;; </span><span class="org-comment">pt &#12392;&#12459;&#12540;&#12477;&#12523;&#12398;&#20301;&#32622;&#12364;&#21516;&#12376;&#12395;&#12394;&#12427;&#12414;&#12391;&#32368;&#12426;&#36820;&#12377;
</span>  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#31561;&#12375;&#12356;&#22580;&#21512;&#12399;&#26368;&#24460;&#12414;&#12391;&#36914;&#12435;&#12384;&#12392;&#12356;&#12358;&#12371;&#12392;&#12391;&#20966;&#29702;&#32066;&#20102;
</span>  (<span class="org-keyword">while</span> (not (equal pt (point)))
    <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12356;&#12414;&#12398;&#12459;&#12540;&#12477;&#12523;&#12398;&#20301;&#32622;&#12434;&#35226;&#12360;&#12390;&#12362;&#12367;
</span>    (<span class="org-keyword">setq</span> pt (point))
    (<span class="org-keyword">let</span> ((link <span class="org-comment-delimiter">; </span><span class="org-comment">posts &#19979;&#12398;&#12501;&#12449;&#12452;&#12523;&#12408;&#12398;&#12522;&#12531;&#12463;
</span>           (concat <span class="org-string">"./posts/"</span>
                   (org-element-property <span class="org-builtin">:FILENAME</span> (org-element-at-point))
                   <span class="org-string">".org"</span>))

          (title (org-get-heading t)) <span class="org-comment-delimiter">; </span><span class="org-comment">h1 &#12434;&#12479;&#12452;&#12488;&#12523;&#12392;&#12377;&#12427;
</span>          (pubdate (org-element-property <span class="org-builtin">:PUBDATE</span> (org-element-at-point))) <span class="org-comment-delimiter">; </span><span class="org-comment">&#20844;&#38283;&#26085;&#12434;&#21462;&#24471;
</span>          (description (org-element-property <span class="org-builtin">:DESCRIPTION</span> (org-element-at-point))) <span class="org-comment-delimiter">; </span><span class="org-comment">&#35443;&#32048;&#12434;&#21462;&#24471;
</span>          )

      <span class="org-comment-delimiter">;; </span><span class="org-comment">index.org &#12501;&#12449;&#12452;&#12523;&#12434;&#38283;&#12367;
</span>      (find-index-file)

      <span class="org-comment-delimiter">;; </span><span class="org-comment">index.org &#12395;&#26360;&#12365;&#36796;&#12416;
</span>      (insert (format <span class="org-string">"* [[%s][%s]]\n"</span> link title))
      (insert <span class="org-string">"#+HTML: &lt;div class=\"info\"&gt;\n"</span>)
      (insert (format <span class="org-string">"#+HTML: &lt;div&gt;&lt;span class=\"date\"&gt;%s&lt;/span&gt;&lt;/div&gt;\n"</span>
                      (html-escape (strip-time pubdate))))
      (insert <span class="org-string">"#+HTML: &lt;/div&gt;\n"</span>)
      (insert <span class="org-string">"\n"</span>)
      (insert description)
      (insert <span class="org-string">"\n"</span>)
      (save-buffer)

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#20803;&#12398;&#22580;&#25152;&#12395;&#25147;&#12427;
</span>      (find-file <span class="org-string">"posts.org"</span>)
      (goto-char pt))
    <span class="org-comment-delimiter">;; </span><span class="org-comment">&#27425;&#12398; h1 &#12395;&#31227;&#21205;&#12377;&#12427;
</span>    <span class="org-comment-delimiter">;; </span><span class="org-comment">&#26368;&#24460;&#12398;&#22580;&#21512;&#12399;&#31227;&#21205;&#12391;&#12365;&#12394;&#12356;&#12398;&#12391;&#21205;&#12363;&#12394;&#12356;
</span>    (org-forward-heading-same-level 1)))
</pre>
</div>


<p>
これを実行すると…
</p>

<div class="org-src-container">
<pre class="src src-shell">emacs --batch -l generate-index.el 
</pre>
</div>

<p>
次のような <code>index.org</code> ファイルが作成されます。
</p>

<pre class="example" id="orgce51a73">
#+TITLE: 私のWebサイト!
#+HTML_HEAD: &lt;meta name="viewport" content="width=device-width, initial-scale=1"/&gt;
#+HTML_HEAD: &lt;link rel="stylesheet" href="/static/css/base.css"/&gt;
#+OPTIONS: email:nil num:nil toc:nil
#+DESCRIPTION: 私の Web サイト &amp;amp;&amp;amp;&amp;amp; デモ &amp;amp;&amp;amp;&amp;amp;
* [[./posts/article3.org][記事3]]
#+HTML: &lt;div class="info"&gt;
#+HTML: &lt;div&gt;&lt;span class="date"&gt;&amp;lt;2024-12-23 月&amp;gt;&lt;/span&gt;&lt;/div&gt;
#+HTML: &lt;/div&gt;

みっつめの記事です
* [[./posts/article2.org][記事2]]
#+HTML: &lt;div class="info"&gt;
#+HTML: &lt;div&gt;&lt;span class="date"&gt;&amp;lt;2024-12-22 日&amp;gt;&lt;/span&gt;&lt;/div&gt;
#+HTML: &lt;/div&gt;

ふたつめの記事です
* [[./posts/article1.org][記事1]]
#+HTML: &lt;div class="info"&gt;
#+HTML: &lt;div&gt;&lt;span class="date"&gt;&amp;lt;2024-12-21 Fri&amp;gt;&lt;/span&gt;&lt;/div&gt;
#+HTML: &lt;/div&gt;

ひとつめの記事です
</pre>

<p>
このように posts.org を走査することでいい感じに
<code>index.org</code> を作成することができます。
</p>
</div>
</div>
<div id="outline-container-2024-12-21-posts-to-posts-filename" class="outline-4">
<h4 id="2024-12-21-posts-to-posts-filename"><code>posts.org</code> から <code>posts/&lt;filename&gt;.org</code> を作成する</h4>
<div class="outline-text-4" id="text-2024-12-21-posts-to-posts-filename">
<p>
以下のスクリプトを作成することで、
<code>posts/</code> 以下に詳細記事ファイルを作成します。
(なお、実際には ox-rss で RSS を生成していたり、
タグの一覧ページへのリンクを張ったりと色々しているせいで複雑なのでここでは簡略化しています)
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(find-file <span class="org-string">"posts.org"</span>)

<span class="org-comment-delimiter">;; </span><span class="org-comment">html-escape &#12377;&#12427;
</span>(<span class="org-keyword">defun</span> <span class="org-function-name">html-escape</span> (str)
  (<span class="org-keyword">let*</span> ((str (string-replace <span class="org-string">"&amp;"</span> <span class="org-string">"&amp;amp;"</span> str))
         (str (string-replace <span class="org-string">"&lt;"</span> <span class="org-string">"&amp;lt;"</span> str))
         (str (string-replace <span class="org-string">"&gt;"</span> <span class="org-string">"&amp;gt;"</span> str))
         (str (string-replace <span class="org-string">"\""</span> <span class="org-string">"&amp;quot;"</span> str)))
    str))

<span class="org-comment-delimiter">;; </span><span class="org-comment">posts &#12487;&#12451;&#12524;&#12463;&#12488;&#12522;&#12434;&#20316;&#25104;
</span>(make-directory <span class="org-string">"./posts"</span>)

<span class="org-comment-delimiter">;; </span><span class="org-comment">posts.org &#12434;&#38283;&#12367;
</span>(<span class="org-keyword">let</span> ((pt nil))          <span class="org-comment-delimiter">; </span><span class="org-comment">pt &#12399;&#12459;&#12540;&#12477;&#12523;&#12398;&#20301;&#32622;&#12434;&#35352;&#37682;&#12375;&#12390;&#12362;&#12367;&#12383;&#12417;&#12398;&#22793;&#25968;
</span>  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12501;&#12449;&#12452;&#12523;&#12398;&#26368;&#23567;&#12398; heading &#12414;&#12391;&#12459;&#12540;&#12477;&#12523;&#12434;&#31227;&#21205;
</span>  (org-next-visible-heading 1)
  <span class="org-comment-delimiter">;; </span><span class="org-comment">pt &#12392;&#12459;&#12540;&#12477;&#12523;&#12398;&#20301;&#32622;&#12364;&#21516;&#12376;&#12395;&#12394;&#12427;&#12414;&#12391;&#32368;&#12426;&#36820;&#12377;
</span>  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#31561;&#12375;&#12356;&#22580;&#21512;&#12399;&#26368;&#24460;&#12414;&#12391;&#36914;&#12435;&#12384;&#12392;&#12356;&#12358;&#12371;&#12392;&#12391;&#20966;&#29702;&#32066;&#20102;
</span>  (<span class="org-keyword">while</span> (not (equal pt (point)))
    <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12356;&#12414;&#12398;&#12459;&#12540;&#12477;&#12523;&#12398;&#20301;&#32622;&#12434;&#35226;&#12360;&#12390;&#12362;&#12367;
</span>    (<span class="org-keyword">setq</span> pt (point))
    (<span class="org-keyword">let</span> ((title (org-get-heading t))
          (link <span class="org-comment-delimiter">; </span><span class="org-comment">posts &#19979;&#12398;&#12501;&#12449;&#12452;&#12523;&#12408;&#12398;&#12522;&#12531;&#12463;
</span>           (concat <span class="org-string">"./posts/"</span>
                   (org-element-property <span class="org-builtin">:FILENAME</span> (org-element-at-point))
                   <span class="org-string">".org"</span>))
          (pubdate (org-element-property <span class="org-builtin">:PUBDATE</span> (org-element-at-point)))
          (description (org-element-property <span class="org-builtin">:DESCRIPTION</span> (org-element-at-point))))
      (<span class="org-keyword">when</span> (file-exists-p link)
        (princ <span class="org-string">"&#12456;&#12521;&#12540;: &#21516;&#12376;&#12497;&#12473;&#12398;&#35352;&#20107;&#12364;&#23384;&#22312;&#12375;&#12414;&#12377;"</span>)
        (exit 1))

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#29694;&#22312;&#20301;&#32622;&#12398;&#35352;&#20107;&#20840;&#20307;&#12434;&#12467;&#12500;&#12540;
</span>      (org-copy-subtree)

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#35352;&#20107;&#12501;&#12449;&#12452;&#12523;&#12434;&#38283;&#12367;
</span>      (find-file link)
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12479;&#12452;&#12523;&#12488;&#12523;&#12434;&#25407;&#20837;
</span>      (insert (format <span class="org-string">"#+TITLE: %s\n"</span> title))
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#35352;&#20107;&#12398;&#20844;&#38283;&#26085;&#12434;&#35373;&#23450;
</span>      (insert (format <span class="org-string">"#+DATE: %s\n"</span> pubdate))
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12354;&#12427;&#22580;&#21512;&#12399; DESCRIPTION &#12434;&#35373;&#23450;
</span>      (<span class="org-keyword">when</span> description
        (insert (format <span class="org-string">"#+DESCRIPTION: %s\n"</span> description)))

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12371;&#12371;&#12391;&#35352;&#20107;&#20840;&#20307;&#12434;&#12506;&#12540;&#12473;&#12488;
</span>      (yank)

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12501;&#12449;&#12452;&#12523;&#12398;&#19968;&#30058;&#19978;&#12395;&#25147;&#12427;
</span>      (goto-char (point-min))
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#26368;&#21021;&#12398; h1 &#12395;&#31227;&#21205;&#12377;&#12427;
</span>      (org-next-visible-heading 1)
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12503;&#12525;&#12497;&#12486;&#12451;&#37096;&#20998;&#12434;&#21066;&#38500;&#12377;&#12427;
</span>      (<span class="org-keyword">let</span> ((begin (car (org-get-property-block)))
            (end (cdr (org-get-property-block))))
        (kill-region begin end))
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12414;&#12383;&#12501;&#12449;&#12452;&#12523;&#12398;&#26368;&#21021;&#12395;&#25147;&#12427;
</span>      (goto-char (point-min))
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#26368;&#21021;&#12398;&#12504;&#12483;&#12480;&#12540;&#12395;&#31227;&#21205;&#12377;&#12427;
</span>      (org-next-visible-heading 1)
      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#12479;&#12452;&#12488;&#12523;&#12398;&#12504;&#12483;&#12480;&#12399;&#19981;&#35201;&#12394;&#12398;&#12391;&#21066;&#38500;&#12377;&#12427;
</span>      <span class="org-comment-delimiter">;; </span><span class="org-comment">:PROPETY: &#12392; :END &#12398;&#34892;&#12418;&#28040;&#12377;&#12363;&#12425;3&#34892;&#28040;&#12377;&#24517;&#35201;&#12354;&#12426;
</span>      (kill-line 3)

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#25237;&#31295;&#26085;&#12434;&#25407;&#20837;
</span>      (insert (format <span class="org-string">"#+HTML: &lt;div class=\"publish-date-wrap\"&gt;&lt;div class=\"publish-date\"&gt;&#25237;&#31295;&#26085;: %s&lt;/div&gt;&lt;/div&gt;\n"</span>
                      (html-escape
                       (substring pubdate
                                  1
                                  (- (length pubdate) (length pubdate) 7)))))

      <span class="org-comment-delimiter">;; </span><span class="org-comment">1&#27573;&#38542;&#28961;&#39364;&#12395;&#28145;&#12367;&#12394;&#12387;&#12390;&#12356;&#12427;&#12398;&#12391;&#12289;
</span>      <span class="org-comment-delimiter">;; </span><span class="org-comment">1&#27573;&#38542;&#12384;&#12369;&#27973;&#12367;&#12377;&#12427;
</span>      (goto-char (point-min))
      (<span class="org-keyword">let</span> ((pt2 (point)))
        (<span class="org-keyword">while</span> (not (org-next-visible-heading 1))
          (org-promote)))

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#20445;&#23384;
</span>      (save-buffer)

      <span class="org-comment-delimiter">;; </span><span class="org-comment">&#20803;&#12398;&#20301;&#32622;&#12395;&#25147;&#12427;
</span>      (find-file <span class="org-string">"../posts.org"</span>)
      (goto-char pt))
    (org-forward-heading-same-level 1)))
</pre>
</div>

<p>
これを実行すると…
</p>

<div class="org-src-container">
<pre class="src src-shell">emacs --batch -l generate-posts.el 
</pre>
</div>

<p>
<code>posts</code> 下に以下ファイルが作成されます。
</p>

<p>
たとえば <code>posts/article1.org</code> はこんな感じです。
</p>

<div class="org-src-container">
<pre class="src src-org"><span class="org-org-document-info-keyword">#+TITLE:</span> <span class="org-org-document-title">&#35352;&#20107;1
</span><span class="org-org-document-info-keyword">#+DATE:</span> <span class="org-org-document-info">&lt;2024-12-21 Fri 00:00&gt;
</span><span class="org-org-meta-line">#+DESCRIPTION: &#12402;&#12392;&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12377;</span>
<span class="org-org-meta-line">#+HTML: &lt;div class="publish-date-wrap"&gt;&lt;div class="publish-date"&gt;&#25237;&#31295;&#26085;: 2024-12-21 Fri&lt;/div&gt;&lt;/div&gt;</span>

<span class="org-org-level-1">* &#12399;&#12376;&#12417;&#12395;</span>

&#12371;&#12398;&#35352;&#20107;&#12399;1&#12388;&#12417;&#12391;&#12377;

<span class="org-org-level-1">* &#12362;&#12431;&#12426;&#12395;</span>

1&#12388;&#12417;&#12398;&#35352;&#20107;&#12391;&#12375;&#12383;
</pre>
</div>
</div>
</div>
<div id="outline-container-2024-12-21-emacs-statc-website-generator-2" class="outline-4">
<h4 id="2024-12-21-emacs-statc-website-generator-2">Emacs を静的サイトジェネレータにする</h4>
<div class="outline-text-4" id="text-2024-12-21-emacs-statc-website-generator-2">
<p>
これ準備ができました。
スクリプトを次の順番で実行すれば、
<code>posts.org</code> から <code>index.org</code> と
<code>posts/&lt;filename&gt;.org</code> を作成します。
配置された状態で <code>org-publish</code> を実行すれば、
<code>site</code> ディレクトリにWeb サイトができます。
</p>

<div class="org-src-container">
<pre class="src src-shell">emacs --batch -l generate-index.el 
emacs --batch -l generate-posts.el 
emacs --batch -l publish.el -f publish-www
</pre>
</div>

<p>
これで完成です。
</p>

<p>
私のサイトはこんな感じで、
Emacs を静的サイトジェネレータとして利用し、
サイトを作っています。
</p>
</div>
</div>
</div>
<div id="outline-container-2024-12-21-owarini" class="outline-3">
<h3 id="2024-12-21-owarini">おわりに</h3>
<div class="outline-text-3" id="text-2024-12-21-owarini">
<p>
私はこんな感じで Emacs で個人サイトを構築しています。
Emacs って本当に何でもできますね。
</p>

<p>
私は本当はどちらかというと関数型プログラミングをしたいのですが、Emacs でこういうことをするとゴリゴリの手続き型プログラミングになりやすいのでそこは苦しいところです。
このあたりの問題を解決したい場合は、
org-mode のファイルを解析するところまでは Emacs でやって、
必要な情報をS式とか JSON で出力して別のプログラミング言語で処理するといいと思います。
</p>

<p>
とりあえずのやっつけで作ってしまった感はあるのですが、
そもそも大したことはしていないためメンテナンス性において特に課題はないため、
今後も引き続きこの仕組みでこのサイトを運用していきたいと思います。
</p>

<p>
また、似たような仕組みで<a href="https://diary.tojo.tokyo">TojoQKの日記</a>というサイトも運営しています。
こちらは比較的どうでもいい記事を置く場所となっているので、
興味があればこちらも見ていってください。
</p>

<p>
最後まで読んでくれてありがとうございます。
Emacs の素晴しさが伝わっていれば幸いです。
</p>
</div>
</div>
<div id="outline-container-2024-12-21-omake" class="outline-3">
<h3 id="2024-12-21-omake">おまけ</h3>
<div class="outline-text-3" id="text-2024-12-21-omake">
</div>
<div id="outline-container-2024-12-21-infra" class="outline-4">
<h4 id="2024-12-21-infra">インフラ</h4>
<div class="outline-text-4" id="text-2024-12-21-infra">
<p>
詳しくは説明しないですが、
私のサイトは VPS で <a href="https://guix.gnu.org/">GNU Guix System</a> という OS を動かしているサーバーの nginx で配信しています。
</p>

<p>
AWS で S3 と CloundFront を使うなどをすればもっと安く運用できるというのはそうなのですが、
個人的な心情として趣味で AWS を使いたくないというのがあります。
私は GNU Guix System が大好きであり、サーバーメンテナンスすること自体が趣味ということもあるので仕方ありません。
(といっても、個人的なデータ置き場としてS3 は活用していますが…)
</p>

<p>
また、私の Web サーバーは別のサイトへのリバースプロキシをするとか、<a href="https://certbot.eff.org/#main-content">Certbot</a> で複数のドメインのSSL証明書を管理するというような大切な仕事もしているので、一概に高いとは言い切れないところがあるわけです。
</p>

<p>
外形監視には UptimeRobot を使っています。
また、一応 Zabbix サーバーの監視対象となっていて、
ディスク使用率とか CPU/メモリの使用率なども監視しています。
</p>
</div>
</div>
<div id="outline-container-2024-12-21-deploy" class="outline-4">
<h4 id="2024-12-21-deploy">デプロイ</h4>
<div class="outline-text-4" id="text-2024-12-21-deploy">
<p>
デプロイは私の git サーバーに push すると、
CI が回ってに自動的にデプロイされるようになっています。
</p>

<p>
<code>main</code> ブランチに push すると記事が公開され、
その他のブランチに push するとテスト環境に記事が公開されます。
</p>

<p>
<code>git push</code> で自動的に記事が公開されると、とっても快適なのでこういう感じにするのはおすすめです。
</p>

<p>
CI は <a href="https://laminar.ohwg.net/">Laminar CI</a> というのを使っていて、
git のフックを起点にデプロイを実行しています。
CI サーバーで Emacs をバッチ実行して、
Web サーバーに rsync してデプロイまでしています。
</p>

<p>
Emacs でバッチ実行していると思うと面白いですね。
</p>
</div>
</div>
</div>
]]></description>
</item>
<item>
<title>GNU GuileのHTTPレスポンスで日本語が文字化けする問題の解決法</title>
<link>https://www.tojo.tokyo/posts/gnu-guile-change-port-encoding.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/gnu-guile-change-port-encoding.html</guid>
<pubDate>Sat, 30 Nov 2024 18:02:00 +0000</pubDate>
<category><![CDATA[Guile]]></category>
<category><![CDATA[Scheme]]></category>
<description><![CDATA[<p>
GNU Guile でHTTPレスポンスを処理するプログラムを書いていて、
日本語が文字化けする問題ではまって1時間くらい時間を溶かしました。
</p>

<p>
公式ドキュメントをみれば分かるというのはそうなのですが、
求めている情報がどこにあるのかよく分からず迷走したので、
解決方法を備忘録として残しておきます。
</p>

<p>
結論としては、ただの port のエンコーディングの問題だったのですが、
手元のファイルを <code>call-with-input-file</code> などで開いたときには、
問題なく日本語を扱えることから port 側の問題だと思わず、
HTTP関連特有の問題かと思って調べたのではまりました。
</p>
<div id="outline-container-2024-11-30-usage" class="outline-3">
<h3 id="2024-11-30-usage">前提: GNU Guile の http クライアントの使い方</h3>
<div class="outline-text-3" id="text-2024-11-30-usage">
<p>
<a href="https://www.gnu.org/software/guile/manual/html_node/Web.html">GNU Guile Reference Manual の 7.3 HTTP, the Web, and All That</a> に
Guile で HTTP プロトコルを扱う方法が記載されています。
</p>

<p>
たとえば、ある url に対して POST メソッドで<a href="https://www.gnu.org/software/guile/manual/html_node/Requests.html">リクエストを投げる</a>場合は次のようにします。
</p>

<div class="org-src-container">
<pre class="src src-scheme">(<span class="org-keyword">define</span> <span class="org-function-name">response</span>
  (http-request uri
                <span class="org-builtin">#:body</span> body
                <span class="org-builtin">#:method</span> 'POST
                <span class="org-builtin">#:streaming?</span> #t))
</pre>
</div>

<p>
<code>http-request</code> の戻りとして <a href="https://www.gnu.org/software/guile/manual/html_node/Responses.html">response</a> というオブジェクトが得られます。
これを処理すれば、HTTPネットワーク上のリソースを扱うことができます。
</p>

<p>
<code>(response-body-port response)</code> でテキストのポートが得られ、
body 部を読み取ることができるのですが、
このときに日本語が文字化けしてはまりました。
</p>
</div>
</div>
<div id="outline-container-2024-11-30-port-encoding" class="outline-3">
<h3 id="2024-11-30-port-encoding">解決方法: port のエンコーディングを確認し変更する</h3>
<div class="outline-text-3" id="text-2024-11-30-port-encoding">
<p>
<a href="https://www.gnu.org/software/guile/manual/html_node/Encoding.html">GNU Guile Reference Manual の 6.12.3 Encoding の節</a>に記載があるように、
port にはエンコーディングの仕方が設定されており、
GNU Guile では <code>port-encoding</code> でポートのエンコーディングの確認、
<code>set-port-encoding!</code> でポートのエンコーディングの変更ができます。
</p>

<p>
私の場合はポートのエンコーディングが <code>ISO-8859-1</code> になっていたせいで、
文字化けが発生していました。
</p>

<div class="org-src-container">
<pre class="src src-scheme">scheme@(guile-user)&gt; (port-encoding (response-body-port response))
$87 = <span class="org-string">"ISO-8859-1"</span>
</pre>
</div>

<p>
これを <code>set-port-encoding!</code> を使って <code>UTF-8</code> にすれば解決です。
</p>

<div class="org-src-container">
<pre class="src src-scheme">scheme@(guile-user)&gt; (<span class="org-keyword">define</span> <span class="org-function-name">port</span> (response-body-port response))
scheme@(guile-user)&gt; (port-encoding port)
$89 = <span class="org-string">"ISO-8859-1"</span>
scheme@(guile-user)&gt; (set-port-encoding! port <span class="org-string">"UTF-8"</span>)
scheme@(guile-user)&gt; (port-encoding port)
$90 = <span class="org-string">"UTF-8"</span>
</pre>
</div>
</div>
</div>
<div id="outline-container-2024-11-30-owarini" class="outline-3">
<h3 id="2024-11-30-owarini">おわりに</h3>
<div class="outline-text-3" id="text-2024-11-30-owarini">
<p>
GNU Guile の日本語の情報を増やし、
GNU Guile を使ってみようと思う人が増えればと思い記事にしてみました。
</p>

<p>
GNU Guile ではまってもドキュメントを漁ればだいたいなんとかなるので、
GNU か Scheme が好きな人は是非使ってみてください。
</p>

<p>
今後も、GNU Guile ではまったことを記事にしていき、
日本語の知見を増やしていければと思います。
</p>
</div>
</div>
]]></description>
</item>
<item>
<title>素のGNOMEを知る 〜「集中」のためのデスクトップ環境〜</title>
<link>https://www.tojo.tokyo/posts/understanding-vanilla-gnome.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/understanding-vanilla-gnome.html</guid>
<pubDate>Sun, 21 Jul 2024 23:20:00 +0000</pubDate>
<category><![CDATA[GNOME]]></category>
<description><![CDATA[<div id="outline-container-org428ceea" class="outline-3">
<h3 id="org428ceea">はじめに</h3>
<div class="outline-text-3" id="text-org428ceea">
<p>
GNU/Linux では GNOME が人気のデスクトップ環境だが、よく使われているのは Ubuntu に搭載されている GNOME だと思う。
しかし、Ubuntu の GNOME はデフォルトでドックを提供していたりデスクトップに物を置くための拡張を入れていて、
GNOME を Windows や macOS の UI に近づけてから配布をしている。
</p>

<p>
そのため、素の状態の GNOME を使ったことのある人は意外と少ないのではないかと考えたため、
素の GNOME がどのようなものなのかについて語る。
</p>
</div>
</div>
<div id="outline-container-org76eb64d" class="outline-3">
<h3 id="org76eb64d">手元の GNOME の実行環境</h3>
<div class="outline-text-3" id="text-org76eb64d">
<dl class="org-dl">
<dt>OS</dt><dd>Guix System</dd>
<dt>GNOME のバージョン</dt><dd>44.10</dd>
<dt>ウィンドウシステム</dt><dd>Wayland</dd>
</dl>
</div>
</div>
<div id="outline-container-org3d6ffb8" class="outline-3">
<h3 id="org3d6ffb8">GNOME にないもの</h3>
<div class="outline-text-3" id="text-org3d6ffb8">
<p>
一般的なデスクトップには次の機能があるが、GNOME にはない。
</p>

<dl class="org-dl">
<dt>常時表示されるウィンドウのリスト</dt><dd>Windows ではタスクバー、macOS ではドックとして存在する機能。いまどのソフトウェアが起動しているかを確認することができる</dd>
<dt>常時表示されるアプリケーションランチャー</dt><dd>上述したタスクバーやドックが兼ている機能で、お気に入りのアプリケーションをいつでも起動できる。起動できるソフトウェアは常に画面上に表示されている。</dd>
<dt>デスクトップにファイルを置く機能</dt><dd>GNOME ではデスクトップはファイルを置く場所ではなくなっている。ただの背景？</dd>
<dt>システムトレイ機能</dt><dd>GNOME ではシステムトレイアイコンは廃止された。ないと普通に不便。</dd>
<dt>最小化/最大化ボタン</dt><dd>有効にすることは可能だがデフォルトで無効となっている。GNOME が提供している「設定」からは有効にできない。</dd>
</dl>

<p>
以上の機能が GNOME にない。これらは Windows や macOS などの既存の UI に慣れ親しんだユーザーにとっては困惑する部分だと思う。
実際、Ubuntu ではこれらの機能のうち重要と思われるドックとデスクトップにファイルを置く拡張が最初から入っている。
このため、Ubuntu で GNOME を使う場合には割と慣れ親しんだ UI に感じることだろう。
</p>

<p>
対して素の GNOME を使った場合の感想はそうではない。
いままでに親しんできたタスクバーやドックはない。
GNU/Linux 上の GNOME 以外のデスクトップ環境にはだいたいタスクバーに相当するものがある(twm やタイル型を除く)。
つまり普通はタスクバーやドックはあるものでありない方が異端である。
</p>

<p>
意外に思うかもしれないが、GNOME は既存の UI から脱却して独自路線に突き進む、尖ったデスクトップ環境なのである。
</p>
</div>
</div>
<div id="outline-container-org0bae740" class="outline-3">
<h3 id="org0bae740">素の GNOME に慣れるまでの流れ</h3>
<div class="outline-text-3" id="text-org0bae740">
<p>
私は GNOME のこういった方針がおかしいと思って GNOME を10年近く避けてきた。
しかし、最終的には GNOME に慣れて、GNOME のデザインは素晴しいとすら感じている。
それまでの経緯について紹介する。
</p>
</div>
<div id="outline-container-org4d10c3c" class="outline-4">
<h4 id="org4d10c3c">前提</h4>
<div class="outline-text-4" id="text-org4d10c3c">
<p>
自分はいままで Xfce4, LXDE, KDE, MATE, Cinnamon などの、通常の常識的な UI を提供するデスクトップを使ってきている。
タイル型マネージャとしては StumpWM や EXWM などを使っていた時期もそこそこの期間あるが、
最終的には普通のデスクトップの方が自分に馴染むと感じている。
</p>
</div>
</div>
<div id="outline-container-org8324188" class="outline-4">
<h4 id="org8324188">きっかけ</h4>
<div class="outline-text-4" id="text-org8324188">
<p>
最近になって GNU Guix System 環境でよくサポートされた Wayland 環境を使うのに
GNOME を選ぶと便利という理由で再度使ってみようと考えた。
</p>
</div>
</div>
<div id="outline-container-orgc638ce4" class="outline-4">
<h4 id="orgc638ce4">Dash to Panel の導入と懸念</h4>
<div class="outline-text-4" id="text-orgc638ce4">
<p>
GNOME に移行し調査したところ、 Dash to Panel という拡張を入れてタスクバーを導入することで、
快適に使えると分かり一週間程度は Dash to Panel ありきで使っていたが、
さらに一週間程度経過して長期的に GNOME 本体とは異なるコンポーネントに深く依存することにリスクを感じるようになった。
Dash to Panel があればそればかり使うので、もはや GNOME ではなくて Dash to Panel を使っているような気さえしてくる。
</p>
</div>
</div>
<div id="outline-container-orge8718e7" class="outline-4">
<h4 id="orge8718e7">GNOME のデザイナーを信じてみる</h4>
<div class="outline-text-4" id="text-orge8718e7">
<p>
そこで GNOME について再考し、
GNOME の設計者がタスクバーやドックが不要という姿勢を頑なに崩さないのには何か理由があるのではないかと思うようになった。
そもそも私はコンピュータの一ユーザーかつ開発者にすぎず、UI/UXの専門家ではない。
おそらくデザインについてよく学んだ人が GNOME を作っているのだろう。
それは最初はユーザーを無視した横暴だと感じていたが、専門家がそこまでそう主張するのであれば GNOME の設計は実は筋が通っているのかもしれない。
</p>
</div>
</div>
<div id="outline-container-org6de3b31" class="outline-4">
<h4 id="org6de3b31">GNOME の挫折</h4>
<div class="outline-text-4" id="text-org6de3b31">
<p>
一度 Dash to Panel を外してみたがすぐに戻した。
</p>

<p>
タスクバーを押せばすぐに起動できるところを無駄にアクティビティを開くのは無駄だと思った。
いま開いている他のウィンドウを開くのにわざわざアクティブティを開くのは無駄だと思った。
すぐに切り替えたり起動したいのに、アクティビティを開くのにモーションが入るのがムカつく。
こういったストレスに耐えられなかったのである。
</p>

<p>
やはり慣れていない UI に移行するのは簡単ではないのである。
</p>
</div>
</div>
<div id="outline-container-org792129e" class="outline-4">
<h4 id="org792129e">GNOME の思想: 「集中」を理解する</h4>
<div class="outline-text-4" id="text-org792129e">
<p>
私は GNOME について学び、GNOME のコンセプトは集中にあるということを理解した。
簡単に使えることやデザインに一貫性があることなども GNOME にとって重要なコンセプトなのかもしれないが、
GNOME の選択を理解するのに最も大きな手掛りになるのは、「いましていることに集中しろ」という考え方である。
</p>

<p>
つまり、GNOME はユーザーの気が散ることを最大限避けてデスクトップを設計しているのである。
いまやっていることに集中し、他のアプリに切り替えるときに初めて「アクティビティ」を押すのだ。
集中を重視しているということを理解すると、GNOME のほとんどの決定について納得ができる。
</p>

<p>
私はコンピュータをそのようには使っていないことに気づいた。
画面には様々な情報が表示されているし、
いまの作業とは関係のないウィンドウをいくつも開いていることはよくあり、
それらを頻繁に切り替えて作業をしていた。
</p>

<p>
そう GNOME に慣れるというのは、単にその UI に慣れるという話ではなかったのだ。
コンピュータとの向き合い方を変えて初めて GNOME の価値に気づくのである。
</p>

<p>
「一つのことに集中する」この意図を理解し、私は再び Dash to Panel を外した。
GNOME の考え方に慣れていないだけで、しばらくの間使ってみて順応すれば便利なのではないかと考えたのだ。
</p>

<p>
それはまさに修行であった。
</p>
</div>
</div>
<div id="outline-container-orgbe33bd9" class="outline-4">
<h4 id="orgbe33bd9">GNOME に慣れる</h4>
<div class="outline-text-4" id="text-orgbe33bd9">
<p>
GNOME のコンセプトが「集中」であることを理解してから、おそらく一週間程度で GNOME に順応した。
もはやアクティビティを開くことに苦を感じず、タスクバーやドックが邪魔だと思うようになった。
アクティビティを開くのにかかるモーションに対してもイライラしなくなった。
むしろあのモーションが操作を心地よくしているような気さえするようになった。
</p>

<p>
GNOME に慣れたことで一つのことに集中しやすくなったような気がする。
</p>
</div>
</div>
</div>
<div id="outline-container-org773d8af" class="outline-3">
<h3 id="org773d8af">GNOME の擁護</h3>
<div class="outline-text-3" id="text-org773d8af">
<p>
先に紹介した GNOME にない機能についてそれぞれ擁護してみようと思う。
なお、それぞれの決定の背景までは追えておらず、以下は私の見解であり GNOME 公式の主張とは無関係のため要注意。
</p>

<p>
GNOME が集中を重視しているという点については、<a href="https://www.gnome.org/">GNOME のホームページ</a> の「Intuitive and Efficient」のパラグラフから読み取れる。
他の「Simple and Easy to Use」や「Finely Crafted」なども GNOME にとって重要な命題なのだとは思うが、
GNOME が何故こうなっているのかという理解に繋がるのは「集中」というコンセプトだと思うため、この点にフォーカスする。
</p>

<p>
いずれも、「集中」というコンセプトを理解すれば納得のいくものだと分かる。
</p>
</div>
<div id="outline-container-org98a729b" class="outline-4">
<h4 id="org98a729b">常時表示されるウィンドウのリスト</h4>
<div class="outline-text-4" id="text-org98a729b">
<p>
作業画面に別のウィンドウの情報が入っていると、いまの作業の集中を妨げるきっかけになるためない。
</p>
</div>
</div>
<div id="outline-container-org3feac78" class="outline-4">
<h4 id="org3feac78">常時表示されるアプリケーションランチャー</h4>
<div class="outline-text-4" id="text-org3feac78">
<p>
作業画面にアプリケーションランチャーがあると、
いまの作業を中断して別のことをしたくなるきっかけになるためない。
</p>
</div>
</div>
<div id="outline-container-org7c4b54b" class="outline-4">
<h4 id="org7c4b54b">デスクトップにファイルを置く機能</h4>
<div class="outline-text-4" id="text-org7c4b54b">
<p>
ウィンドウを小さくしてデスクトップが画面に写ったとき、
背景に置かれているファイルが目に入ることで気が散るのでなくてよい。
</p>
</div>
</div>
<div id="outline-container-orgdbbfc45" class="outline-4">
<h4 id="orgdbbfc45">システムトレイ機能</h4>
<div class="outline-text-4" id="text-orgdbbfc45">
<p>
自動的に表示されるシステムトレイアイコンは集中を妨げるきっかけとなる。
</p>
</div>
</div>
<div id="outline-container-org12296ad" class="outline-4">
<h4 id="org12296ad">最小化ボタン</h4>
<div class="outline-text-4" id="text-org12296ad">
<p>
これは、ウィンドウに対する考え方の問題だと思われる。
</p>

<p>
GNOME にはタスクバーやドックがないため最小化する先がない。
最小化したものがどこにいったのか謎である。
</p>

<p>
最大化ボタンがないのはよく分からない。
私はスクリーンエッジ機能かキーボードショートカットのいずれかで最大化しているが、
これはたしかにちょっと分かりにくいかもしれない。
</p>
</div>
</div>
</div>
<div id="outline-container-org4ee098e" class="outline-3">
<h3 id="org4ee098e">おわりに</h3>
<div class="outline-text-3" id="text-org4ee098e">
<p>
GNOME はユーザーが「集中する」というコンセプトに基づいており、
この考え方を理解すると多くのデザイン上の選択について納得できる。
</p>

<p>
拡張を導入することで Windows や macOS に近づけることも可能だが、
素の GNOME を使うことでその真価を確かめてみてほしい。
</p>

<p>
単なるデザインの違いではなく、コンピュータとの向き合い方を見直すよい機会になるだろう。
</p>

<p>
素の GNOME の魅力を是非体験して欲しい。
</p>
</div>
</div>
]]></description>
</item>
<item>
<title>ノートパソコンを冷やすファンを買った話</title>
<link>https://www.tojo.tokyo/posts/laptop-fan-cool-hands.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/laptop-fan-cool-hands.html</guid>
<pubDate>Fri, 17 May 2024 02:00:00 +0000</pubDate>
<category><![CDATA[商品レビュー]]></category>
<description><![CDATA[<p>
ノートパソコンを冷やすファン(ELECOM の <a href="https://www.elecom.co.jp/products/FAN-U177BK.html">FAN-U177BK</a>)を買ったところいい感じだったので紹介する。
</p>
<div id="outline-container-org2bfd8b3" class="outline-3">
<h3 id="org2bfd8b3">きっかけ</h3>
<div class="outline-text-3" id="text-org2bfd8b3">
<p>
会社でキーボードへのこだわりについての話がされていて、
自分はキーボードはノートパソコンのものを使う派なので疎外感を感じつつ、そのメリットとデメリットについて考えていたところ、
ノートパソコンのキーボードを使うと発熱によって手が温まるのが割と大きめな問題であることに気づいた。
この件についてどうにかならないか調べたところ、何やらファンを買って冷やせばいいという割と普通の答えに行き着いた。
</p>

<p>
最近のノートパソコンは静音化を重視してファンレスにする傾向にあり、
駆動部がなくなって故障点が減るとかうるさくなくなったという利点があるが、
熱くなったときにファンがなくて冷えにくくそれによって手があたたまるという問題を抱えている。
</p>

<p>
この問題の解決に外付けでファンを付けるというのはよい考えだと思い、
ノートパソコンを USB 扇風機で冷やす商品である ELECOM の <a href="https://www.elecom.co.jp/products/FAN-U177BK.html">FAN-U177BK</a> を購入した。
</p>
</div>
</div>
<div id="outline-container-orgfbb69bb" class="outline-3">
<h3 id="orgfbb69bb">製品の紹介など</h3>
<div class="outline-text-3" id="text-orgfbb69bb">
<p>
扇風機とパソコンに傾斜を付けるタイプのスタンドで主にノートパソコンを冷やすための商品だ。
スタンドにノートパソコンが乗ることによって、机との間に隙間ができてそこに風を流すことによって効率良く冷却する仕組みになっている。
リンク先の紹介画像にはキーボードの上に風が通っているかのような矢印があるが、
実際にはそこを風が通ることを期待してはいけない。なので直接キーボードが風で冷やされるということはないので注意が必要だ。
まあ、構造上そこに風が入ると思う方がおかしいかもしれないが、誤解を生む可能性があるのでよくないと思う。
</p>
</div>
</div>
<div id="outline-container-orgedad035" class="outline-3">
<h3 id="orgedad035">使ってみた感想</h3>
<div class="outline-text-3" id="text-orgedad035">
</div>
<div id="outline-container-orga04ac27" class="outline-4">
<h4 id="orga04ac27">手があたたまることがなくなった</h4>
<div class="outline-text-4" id="text-orga04ac27">
<p>
実際に届いて使ってみた感想だが、本当にノートパソコンに熱がこもるということがなくなり、手があたたまることがなくなった。
これは快適である。
私が使っているノートパソコンは下から排熱する機構になっているので、このノートパソコンを冷やすには最適な仕組みといえるだろう。
</p>

<p>
私はノートパソコンが熱くなくても普通に自身の体温によって手が温まっていることがあり、
それでも不快感を覚えるというところがあるのだが、そういったときにノートパソコンの両サイドに手を置くことによって、
簡単に手を冷やすことができるというのは隠れた利点である。
</p>
</div>
</div>
<div id="outline-container-org6d5f48c" class="outline-4">
<h4 id="org6d5f48c">ファンの音について</h4>
<div class="outline-text-4" id="text-org6d5f48c">
<p>
気になる可能性があるのはファンの音だろう。
人によってはうるさいと感じる方もいるかもしれない。
私としては付けっぱなしにしていればあまり気にならない程度の音かなと感じた。
風量は三段階で調節できるのだけど、一番弱いのにすると音は小さくなるのだけど回転数が少ない分低い音がでるので私はそれが気になった。
二段階目か最大の風量にすることでちょうどいい感じの騒音となり逆に気にならない感じがした。
そのため私は常に二段階目以上の強さで利用している。
自分はあまり気にならなかったが人によっては、気になるかもしれないところではあるのでそこは覚悟する必要があるだろう。
</p>
</div>
</div>
<div id="outline-container-org37fee79" class="outline-4">
<h4 id="org37fee79">他のメリットについて</h4>
<div class="outline-text-4" id="text-org37fee79">
<p>
CPU の性能とかにも影響を与える要素なわけでそういった性能上の理由で困っている人にもおすすめだ。
</p>
</div>
</div>
<div id="outline-container-orgdf6ac63" class="outline-4">
<h4 id="orgdf6ac63">USB Type-A での接続が必要な点について</h4>
<div class="outline-text-4" id="text-orgdf6ac63">
<p>
パソコンからUSB経由で電源供給する仕様なのだが規格が USB Type-A であることには注意が必要かもしれない。
最近のパソコンは薄型への需要に答えるためなのか USB Type-C のみ採用していることも少なくない。
その場合は USB Type-A を USB Type-C に変換するアダプタが必要になる。
幸い、私のノートパソコンには USB Type-A のコネクタがあるので問題にならなかった。
</p>
</div>
</div>
</div>
<div id="outline-container-org11d7f24" class="outline-3">
<h3 id="org11d7f24">まとめ</h3>
<div class="outline-text-3" id="text-org11d7f24">
<p>
パソコンによって手を温められてしまう不快さというのは私にとっては割と大きな問題だったので解決してよかった。
同じ問題を抱えているのであれば、おすすめだ。
</p>
</div>
</div>
]]></description>
</item>
<item>
<title>Common Lispを静的型付けの関数型言語にするCoaltonの紹介</title>
<link>https://www.tojo.tokyo/posts/coalton-introduction.html</link>
<author>masaya@tojo.tokyo (Masaya Tojo)</author>
<guid isPermaLink="false">https://www.tojo.tokyo/posts/coalton-introduction.html</guid>
<pubDate>Mon, 11 Dec 2023 00:02:00 +0000</pubDate>
<category><![CDATA[Lisp]]></category>
<category><![CDATA[Coalton]]></category>
<description><![CDATA[<p>
<a href="https://adventar.org/calendars/9364">Lisp Advent Calendar 2023 - Adventar</a> の11日目の記事です。
</p>

<p>
Common Lisp を静的型付けの関数型言語にするライブラリである <a href="https://github.com/coalton-lang/coalton">Coalton</a> を紹介します。
</p>

<p>
まだバージョン1.0には達していない状況ですが、
活発に開発が進められていて確実に完成度が上がっている期待度の高いプロジェクトです。
</p>

<p>
この記事では主に Coalton を採用すると得られるメリットや、
マクロ、Common Lisp との相互運用などの気になる点をピックアップして紹介します。
</p>
<div id="outline-container-about" class="outline-3">
<h3 id="about">Coalton とは</h3>
<div class="outline-text-3" id="text-about">
<p>
<a href="https://github.com/coalton-lang/coalton">Coalton</a> は Common Lisp を静的型付けの秀逸な型システムをもった関数型言語に拡張するライブラリです。
</p>

<p>
Coalton は他の通常の Common Lisp のライブラリと同じ方法で導入でき、
asdf で読み込むだけで簡単に使えます。
</p>

<p>
Coalton は他の Common Lisp のライブラリと共存可能であり、
Coalton のコードを生成するマクロを自分で定義して Coalton をさらに拡張することすら可能です。
Coalton の式は通常の Lisp コードと同じように、REPL で簡単に評価できます。
通常の Common Lisp と書き方が少し異なりますが、まぎれもなく Common Lisp のコードです。
</p>

<p>
Coalton を導入することで一般に言われるような静的型付き言語のメリットをすべて享受できます。
さらに、静的型付きの関数型プログラミング言語でよく採用される代数的データ型や型クラスを活用したプログラミングもできるようになります。
</p>
</div>
<div id="outline-container-common-lisp-potential" class="outline-4">
<h4 id="common-lisp-potential">Coalton が示す Common Lisp の可能性</h4>
<div class="outline-text-4" id="text-common-lisp-potential">
<p>
Coalton は Common Lisp の可能性に限界がないことを示す素晴しい事例の一つだと思います。
研究が進んで新しいプログラミングに関する概念が生まれたときに、
開発者の努力によって追従できるプログラミング言語環境というのはそう多くないでしょう。
Common Lisp は新しい技術を創造したり適応したりすることで進化できるプログラミング言語だということを
Coalton が実際に証明しています。
</p>
</div>
</div>
</div>
<div id="outline-container-how-to-lean" class="outline-3">
<h3 id="how-to-lean">Coalton の使い方を学ぶ方法</h3>
<div class="outline-text-3" id="text-how-to-lean">
<p>
Coalton のリポジトリの <a href="https://github.com/coalton-lang/coalton/tree/main/docs">docs</a> にあるドキュメントが有効な情報源です。
</p>

<p>
まずは <a href="https://github.com/coalton-lang/coalton/blob/main/docs/intro-to-coalton.md">Intro to Coalton</a> から読みましょう。
このドキュメントを上から下まで読むことで、Coalton を使い方が分かります。
</p>

<p>
<a href="https://github.com/coalton-lang/coalton/tree/main/examples">examples</a> には Coalton を使ったプログラムの例があるので、
こちらを参考にするのもおすすめです。
</p>
</div>
</div>
<div id="outline-container-advantages" class="outline-3">
<h3 id="advantages">Coalton の魅力</h3>
<div class="outline-text-3" id="text-advantages">
<p>
Coalton を導入することで得られるメリットを重要度の高い順に紹介します。
</p>
</div>
<div id="outline-container-exhaustive-check" class="outline-4">
<h4 id="exhaustive-check">網羅性チェック</h4>
<div class="outline-text-4" id="text-exhaustive-check">
<p>
全ての場合を網羅できていないとき、プログラムは意図しない挙動を引き起こします。
</p>

<p>
たとえば、ステータスを見てそれぞれのステータスに対応した何らかの処理をする必要があるとします。
次のステータスを文字列に変換するコードを書いたとしましょう。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:manage-status</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:coalton</span>
        <span class="org-builtin">#:coalton-prelude</span>))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:manage-status</span>)

(named-readtables:in-readtable coalton:coalton)

(coalton-toplevel
  (define-type Status
    Open
    Showing
    Closed)

  (define-instance (Into Status String)
    (define (into s)
      (match s
        ((Showing) <span class="org-string">"&#19978;&#26144;&#20013;"</span>)
        ((Open) <span class="org-string">"&#38283;&#22580;"</span>)
        ((Closed) <span class="org-string">"&#32066;&#20102;"</span>)))))
</pre>
</div>

<p>
この後に <code>Preparing</code> というステータスを追加します。
このとき、Status が一つ増えたので使っている全ての箇所について漏れがないか確認する必要があります。
</p>

<p>
Coalton では網羅性チェックが機能するので、Status を網羅できていない箇所があればコンパイラが警告を出してくれます。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:manage-status</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:coalton</span>
        <span class="org-builtin">#:coalton-prelude</span>))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:manage-status</span>)

(named-readtables:in-readtable coalton:coalton)

(coalton-toplevel
  (define-type Status
    Preparing
    Open
    Showing
    Closed)

  (define-instance (Into Status String)
    (define (into s)
      (match s
        ((Showing) <span class="org-string">"&#19978;&#26144;&#20013;"</span>)
        ((Open) <span class="org-string">"&#38283;&#22580;"</span>)
        ((Closed) <span class="org-string">"&#32066;&#20102;"</span>)))))
</pre>
</div>

<pre class="example" id="orgd0d47a9">
; caught COMMON-LISP:STYLE-WARNING:
;   warn: Non-exhaustive match
;     --&gt; /tmp/manage-status.lisp:18:6
;       |
;    18 |          (match s
;       |  ________^
;       | | _______-
;    19 | ||         ((Showing) "上映中")
;    20 | ||         ((Open) "開場")
;    21 | ||         ((Closed) "終了")))))
;       | ||____________________________- Missing case (PREPARING)
;       | |_____________________________^ non-exhaustive match
;   
; 
; compilation unit finished
;   caught 1 STYLE-WARNING condition
</pre>

<p>
条件や場合を Coalton のデータ型で表現することで、網羅性に関するバグを減らすことができます。
</p>
</div>
</div>
<div id="outline-container-dispatch" class="outline-4">
<h4 id="dispatch">戻り値の型で実装を選択する機能</h4>
<div class="outline-text-4" id="text-dispatch">
<p>
Common Lisp で型変換をするには <code>coerce</code> という関数を使いますが、残念ながらユーザーが定義したデータ型を変換するのには使えません。
そのため、Lisp では一般にユーザーが型変換をする関数を実装する場合にはだいたい次のような名前の関数を書いていると思います。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defun</span> <span class="org-function-name">foo-to-bar</span> (foo)
  &#8230;)

(<span class="org-keyword">defun</span> <span class="org-function-name">foo-&gt;bar</span> (foo)
  &#8230;)
</pre>
</div>

<p>
それに対し、Coalton には <code>Into</code> という型クラスがあり、全ての型変換を <code>Into</code> 型クラスのメソッド <code>into</code> のみで対応できます。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(define-instance (Into Foo Bar)
  (define (into foo)
    &#8230;))
</pre>
</div>

<p>
CLOS のクラスと Coalton の型クラスには他にも違いがあるのですが、
ここでは Coalton の型クラスのメソッドでは戻り値の型で呼び出す実装を特定できるという点に注目します。
</p>

<p>
CLOS の総称関数を使うと引数のオブジェクトをもとにして実装を特定できますが、この仕組みでは戻り値の情報は使えません。
呼び出す実装を動的に決定している以上 <code>coerce</code> 関数のように変換先のヒントを与えない限りは変換関数を CLOS の総称関数の機能だけで実装するのは無理です。
</p>

<div class="org-src-container">
<pre class="src src-lisp"><span class="org-comment-delimiter">;; </span><span class="org-comment">bar &#12463;&#12521;&#12473;&#12391;&#12487;&#12451;&#12473;&#12497;&#12483;&#12481;&#12364;&#12391;&#12365;&#12394;&#12356;&#65281;
</span>(<span class="org-keyword">defmethod</span> <span class="org-function-name">into</span> ((foo foo))
  &#8230;)

<span class="org-comment-delimiter">;; </span><span class="org-comment">&#23455;&#34892;&#26178;&#12395;&#21628;&#12403;&#20986;&#12375;&#12383;&#12479;&#12452;&#12511;&#12531;&#12464;&#12391; foo &#12398;&#22793;&#25563;&#20808;&#12434;&#29305;&#23450;&#12391;&#12365;&#12394;&#12356;&#65281;
</span>(into foo)
</pre>
</div>

<p>
それに対し Coalton では <code>into</code> 関数の戻り値側の型をコンパイル時に知ることができるので戻り値の型から実装を特定できます。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">declare</span> calc-bar (Bar -&gt; &#8230;))
(define (calc-bar bar)
  &#8230;)

<span class="org-comment-delimiter">;; </span><span class="org-comment">&#12467;&#12531;&#12497;&#12452;&#12523;&#26178;&#12395;&#22411;&#25512;&#35542;&#12391; (into foo) &#12398;&#22793;&#25563;&#20808;&#12364; Bar &#12384;&#12392;&#20998;&#12363;&#12427;&#65281;
</span>(calc-bar (into foo))
</pre>
</div>

<p>
CLOS の総称関数と比べて実装の特定に使える情報が一つ増えている分、ディスパッチの能力についていえば純粋にパワーアップしているといえます。
</p>

<p>
他にも <code>Monoid</code> や <code>Applicative</code>, <code>Monad</code> など、
戻り値の型によるディスパッチができないと表現が難しい構造がいくつもありいずれも有用です。
Coalton を導入することでこういった抽象度の高い構造を扱うことができます。
</p>
</div>
</div>
<div id="outline-container-no-omit-nil" class="outline-4">
<h4 id="no-omit-nil">「null安全」になる</h4>
<div class="outline-text-4" id="text-no-omit-nil">
<p>
Coalton はnull安全であり、意図しないところに <code>nil</code> が流れついてきて実行時にエラーになってしまうという問題は生じません。
</p>

<p>
Coalton では <code>Optional</code> という型を使うことで結果がない可能性のある値を表現できます。
次のように Optional 型の値に対して不適切な関数を適用すると実行前に型エラーになります。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:optional-example</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:coalton</span>
        <span class="org-builtin">#:coalton-prelude</span>)
  (<span class="org-builtin">:local-nicknames</span>
   (<span class="org-builtin">#:string</span> <span class="org-builtin">#:coalton-library/string</span>)))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:optional-example</span>)

(named-readtables:in-readtable coalton:coalton)

(coalton-toplevel
  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#36899;&#24819;&#12522;&#12473;&#12488;&#12363;&#12425;&#35201;&#32032;&#12434;&#21462;&#12426;&#20986;&#12377;
</span>  (<span class="org-keyword">declare</span> get-value (Eq <span class="org-builtin">:k</span> =&gt; <span class="org-builtin">:k</span> -&gt; List (Tuple <span class="org-builtin">:k</span> <span class="org-builtin">:v</span>) -&gt; Optional <span class="org-builtin">:v</span>))
  (define (get-value key alist)
    (<span class="org-keyword">do</span> ((Tuple _ value) &lt;- (find (.&lt; (== key) fst) alist))
        (pure value)))

  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#25972;&#24418;&#12377;&#12427;
</span>  (<span class="org-keyword">declare</span> format (Integer -&gt; String -&gt; String))
  (define (format k v)
    (lisp String (k v)
      (cl:format nil <span class="org-string">"~R: ~a"</span> k v)))

  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#36899;&#24819;&#37197;&#21015;&#12363;&#12425;&#12461;&#12540;&#12391;&#21462;&#24471;&#12375;&#12390;&#25972;&#24418;&#12375;&#12383;&#25991;&#23383;&#21015;&#12434;&#36820;&#12377;
</span>  (define (show key alist)
    (format key (get-value key alist))))
</pre>
</div>


<div class="org-src-container">
<pre class="src src-lisp">optional-example.lisp:1:1:
  read-error: 
    COMMON-LISP:READ error during COMMON-LISP:COMPILE-FILE:

      error: Type mismatch
      --&gt; /tmp/optional-example.lisp:26:12
        |
     26 |      (format (get-value key alist))))
        |              ^^^^^^^^^^^^^^^^^^^^^ Expected type 'INTEGER' but got '(OPTIONAL <span class="org-builtin">:A</span>)'


      (in form starting at line: 11, column: 0, position: 220)
</pre>
</div>

<p>
次のように Optional を考慮して修正すれば、型エラーは解消します。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:optional-example</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:coalton</span>
        <span class="org-builtin">#:coalton-prelude</span>)
  (<span class="org-builtin">:local-nicknames</span>
   (<span class="org-builtin">#:string</span> <span class="org-builtin">#:coalton-library/string</span>)))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:optional-example</span>)

(named-readtables:in-readtable coalton:coalton)

(coalton-toplevel
  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#36899;&#24819;&#12522;&#12473;&#12488;&#12363;&#12425;&#35201;&#32032;&#12434;&#21462;&#12426;&#20986;&#12377;
</span>  (<span class="org-keyword">declare</span> get-value (Eq <span class="org-builtin">:k</span> =&gt; <span class="org-builtin">:k</span> -&gt; List (Tuple <span class="org-builtin">:k</span> <span class="org-builtin">:v</span>) -&gt; Optional <span class="org-builtin">:v</span>))
  (define (get-value key alist)
    (<span class="org-keyword">do</span> ((Tuple _ value) &lt;- (find (.&lt; (== key) fst) alist))
        (pure value)))

  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#25972;&#24418;&#12377;&#12427;
</span>  (<span class="org-keyword">declare</span> format (Integer -&gt; String -&gt; String))
  (define (format k v)
    (lisp String (k v)
      (cl:format nil <span class="org-string">"~R: ~a"</span> k v)))

  <span class="org-comment-delimiter">;; </span><span class="org-comment">&#36899;&#24819;&#37197;&#21015;&#12363;&#12425;&#12461;&#12540;&#12391;&#21462;&#24471;&#12375;&#12390;&#25972;&#24418;&#12375;&#12383;&#25991;&#23383;&#21015;&#12434;&#36820;&#12377;
</span>  <span class="org-comment-delimiter">;; </span><span class="org-comment">match &#12391;&#22580;&#21512;&#20998;&#12369;&#12377;&#12427;&#22580;&#21512;
</span>  (define (show/match key alist)
    (match (get-value key alist)
      ((Some value) (Some (format key value)))
      ((None) None)))

  <span class="org-comment-delimiter">;; </span><span class="org-comment">do &#35352;&#27861;&#12434;&#20351;&#12358;&#22580;&#21512;
</span>  (define (show/do key alist)
    (<span class="org-keyword">do</span> (value &lt;- (get-value key alist))
        (pure (format key value))))

  <span class="org-comment-delimiter">;; </span><span class="org-comment">map &#38306;&#25968;&#12434;&#20351;&#12358;&#22580;&#21512;
</span>  (define (show/map key alist)
    (map (format key) (get-value key alist))))
</pre>
</div>

<p>
このように、nil を想定していない関数を nil に適用してしまう問題を完全に回避することができます。
Coalton を導入すれば関数の戻り値が nil である可能性を気にする手間から完全に解放されます。
</p>
</div>
</div>
</div>
<div id="outline-container-use-macro" class="outline-3">
<h3 id="use-macro">Coalton でマクロを使う</h3>
<div class="outline-text-3" id="text-use-macro">
<p>
Common Lisp には、Common Lisp のコードを生成するマクロを書くのが簡単という特徴があります。
Coalton は Common Lisp のコードの一部であるため、Common Lisp で Coalton のコードを書くのもまた簡単です。
そのため、Coalton をマクロを使ってさらに拡張することができます。
簡単にマクロが書けるのは他の静的型付きの関数型言語と比較して大きな強みといえるでしょう。
</p>

<p>
なお、マクロを書くのであれば少なくとも現時点では Coalton で書くのではなくて普通の Common Lisp で書いた方が楽です。
次に説明する <code>validate-with-result</code> でもマクロの実装は Coalton ではなくて Lisp で書いています。
</p>
</div>
<div id="outline-container-validate-with-result" class="outline-4">
<h4 id="validate-with-result">事例: validate-with-result</h4>
<div class="outline-text-4" id="text-validate-with-result">
<p>
<span class="timestamp-wrapper"><span class="timestamp">&lt;2023-12-21 木&gt; </span></span> バリデーションの実装は Result と同型の型でうまくいき、本当に必要だったものは
Applicative でした。Applicative
によるバリデーションは <a href="https://github.com/tojoqk/tokyo.tojo.validation">tokyo.tojo.validation</a> にて実装しているのでよかったら見てみてください。
</p>

<p>
私が Coalton で複数の項目をバリデーションしつつ文字列から適切な型に変換をするようなプログラムを書いていたのですが、
意外とこのような処理を楽にうまく書く方法がなかなか見つかりませんでした。
試行錯誤した結果した結果、マクロを使って構文を定義した方がいいと判断して validate-with-result というプログラムを実装しました。
</p>

<p>
<a href="https://github.com/tojoqk/validate-with-result">tojoqk/validate-with-result: Syntax `let` for delaying result in Coalton.</a>
</p>

<p>
例として、名前、年齢、状態の3つを文字列で渡し、それぞれをパースして適切な型に変換することを考えましょう。
まずはそれぞれのパースする関数を定義します。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:validate-with-result-example</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:coalton</span>
        <span class="org-builtin">#:coalton-prelude</span>)
  (<span class="org-builtin">:local-nicknames</span>
   (<span class="org-builtin">#:string</span> <span class="org-builtin">#:coalton-library/string</span>)))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:validate-with-result-example</span>)

(named-readtables:in-readtable coalton:coalton)

(coalton-toplevel
  (define parse-name Ok)

  (define (parse-age x)
    (match (string:parse-int x)
      ((Some n)
       (<span class="org-keyword">if</span> (&lt;= 1 n)
           (Ok n)
           (Err (make-list <span class="org-string">"parse-age-error (negative)"</span>))))
      ((None) (Err (make-list <span class="org-string">"parse-age-error"</span>)))))

  (define-type Status
    Sleeping
    Studying)

  (define (parse-status x)
    (match x
      (<span class="org-string">"sleeping"</span> (Ok sleeping))
      (<span class="org-string">"studying"</span> (Ok Studying))
      (_ (Err (make-list <span class="org-string">"parse-status-error"</span>))))))
</pre>
</div>

<p>
ここからが <code>validate-with-result</code> の出番です。
</p>

<p>
<code>validate-with-result:let</code> というマクロを使ってバリデーションを実行します。
構文は次のような感じです。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(validate-with-result:let ((&lt;var1&gt; &lt;result-type-value1&gt;)
                           (&lt;var2&gt; &lt;result-type-value2&gt;)
                           ...)
  &lt;expr&gt; ...)
</pre>
</div>

<p>
全て Ok の場合は <code>validate-with-result:let</code> の <code>&lt;expr&gt;</code> 部分の式 <code>(Tuple3 name age status)</code> の結果が返ります。
</p>

<div class="org-src-container">
<pre class="src src-lisp">VALIDATE-WITH-RESULT-EXAMPLE&gt; (coalton
                               (valdate-with-result:let ((name (parse-name <span class="org-string">"john"</span>))
                                                         (age (parse-age <span class="org-string">"28"</span>))
                                                         (status (parse-status <span class="org-string">"sleeping"</span>)))
                                 (Ok (Tuple3 name age status))))
#.(OK #.(TUPLE3 <span class="org-string">"john"</span> 28 #.SLEEPING))
</pre>
</div>

<p>
<code>age</code> と <code>status</code> のパースに失敗した場合はそれぞれのエラーメッセージを返します。
</p>

<div class="org-src-container">
<pre class="src src-lisp">VALIDATE-WITH-RESULT-EXAMPLE&gt; (coalton
                               (validate-with-result:let ((name (parse-name <span class="org-string">"john"</span>))
                                                          (age (parse-age <span class="org-string">"-28"</span>))
                                                          (status (parse-status <span class="org-string">"playing"</span>)))
                                 (Ok (Tuple3 name age status))))
#.(ERR (<span class="org-string">"parse-age-error (negative)"</span> <span class="org-string">"parse-status-error"</span>))
VALIDATE-WITH-RESULT-EXAMPLE&gt; 
</pre>
</div>

<p>
こんな感じで Coalton の Reuslt 型を活用して簡単にバリデーションを実現できます。
</p>

<p>
このように Coalton でも通常の Common Lisp での開発と同じようにマクロを使うことで言語を拡張することができるのです。
</p>
</div>
</div>
</div>
<div id="outline-container-interop" class="outline-3">
<h3 id="interop">Common Lisp との相互運用</h3>
<div class="outline-text-3" id="text-interop">
<p>
詳細は <a href="https://github.com/coalton-lang/coalton/blob/main/docs/coalton-lisp-interop.md">Coalton-Lisp Interoperation</a> を参照してください。
</p>

<p>
<b><b>2024-02-17 追記</b></b>
</p>

<p>
この記事を書いたときよりも <a href="https://github.com/coalton-lang/coalton/blob/main/docs/coalton-lisp-interop.md">Coalton-Lisp Interoperation</a> の内容が充実しています。
実際に Coalton と Common Lisp
で相互運用する場合にはこのドキュメントを読んで状況にあった対処をするのがよさそうです。
</p>
</div>
<div id="outline-container-lisp-in-coalton" class="outline-4">
<h4 id="lisp-in-coalton">Coalton から Common Lisp を呼ぶ</h4>
<div class="outline-text-4" id="text-lisp-in-coalton">
<p>
<code>lisp</code> という構文を使うことで Coalton から Common Lisp のコードを実行できます。
たとえば次のようにして Common Lisp の format 関数を呼ぶことができます。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:awesome-format</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:coalton</span>
        <span class="org-builtin">#:coalton-prelude</span>))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:awesome-format</span>)

(named-readtables:in-readtable coalton:coalton)

(coalton-toplevel
  (<span class="org-keyword">declare</span> awesome-format (Integer -&gt; String -&gt; String))
  (define (awesome-format i title)
    (lisp String (i title)
      (cl:format nil <span class="org-string">"~@:R ~a"</span> i title))))
</pre>
</div>

<p>
REPL:
</p>

<div class="org-src-container">
<pre class="src src-lisp">AWESOME-FORMAT&gt; (coalton (awesome-format 7 <span class="org-string">"&#12479;&#12452;&#12488;&#12523;"</span>))
<span class="org-string">"VII &#12479;&#12452;&#12488;&#12523;"</span>
</pre>
</div>

<p>
ただし、Common Lisp のコードを呼び出すときに不適切な型を返してしまうと
Coalton システムの健全性を損なう可能性があるため、
Coalton の中から Common Lisp のコードを呼ぶ場合には戻り値の型に注意が必要です。
</p>
</div>
</div>
<div id="outline-container-coalton-in-lisp" class="outline-4">
<h4 id="coalton-in-lisp">Common Lisp から Coalton の関数を呼び出す</h4>
<div class="outline-text-4" id="text-coalton-in-lisp">
<p>
逆に Common Lisp から Coalton の関数を安全に呼ぶ方法ですが、
2023/12/10 の時点では安全に呼ぶ方法がドキュメントに記載されていません。
</p>

<p>
しかし、下記の PR がマージされているためおそらく <code>call-coalton-function</code>
という関数を通して Common Lisp から Coalton の関数を呼ぶのが無難そうです。
<a href="https://github.com/coalton-lang/coalton/pull/660">Friendly interface for calling Coalton function-entry objects from CL</a>
</p>

<p>
次のように Common Lisp のプログラムから Coalton の関数を呼び出すことができます。
</p>

<div class="org-src-container">
<pre class="src src-lisp">(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:awesome-format</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:coalton</span>
        <span class="org-builtin">#:coalton-prelude</span>)
  (<span class="org-builtin">:export</span> <span class="org-builtin">#:awesome-format</span>))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:awesome-format</span>)

(named-readtables:in-readtable coalton:coalton)

(coalton-toplevel
  (<span class="org-keyword">declare</span> awesome-format (Integer -&gt; String -&gt; String))
  (define (awesome-format i title)
    (lisp String (i title)
      (cl:format nil <span class="org-string">"~@:R ~a"</span> i title))))

(<span class="org-keyword">defpackage</span> <span class="org-builtin">#:awsome-format-cl</span>
  (<span class="org-builtin">:use</span> <span class="org-builtin">#:cl</span>))

(<span class="org-keyword">in-package</span> <span class="org-builtin">#:awsome-format-cl</span>)

(<span class="org-keyword">defun</span> <span class="org-function-name">show-title</span> (i title)
  <span class="org-comment-delimiter">;; </span><span class="org-comment">Common Lisp &#12363;&#12425; Coalton &#12398;&#38306;&#25968;&#12434;&#21628;&#12403;&#20986;&#12377;
</span>  (coalton:call-coalton-function awesome-format:awesome-format
                                 i
                                 title))
</pre>
</div>
</div>
</div>
</div>
<div id="outline-container-end" class="outline-3">
<h3 id="end">おわりに</h3>
<div class="outline-text-3" id="text-end">
<p>
Coalton を導入すると Common Lisp でも静的型付けのメリットを享受できるうえに、
網羅性チェックや、戻り値の型によるディスパッチ、null安全性という強力な機能を使うことができることを紹介しました。
</p>

<p>
そして Coalton でも Lisp の最大級の能力であるマクロを活用できることを説明し、
最後に Coalton と Common Lisp での相互運用が可能なことにについて簡単に説明しました。
</p>

<p>
このように Coalton には Common Lisp の開発に劇的な変化をもたらす可能性があります。
是非 Coalton について興味を持っていただければと思います。
</p>
</div>
</div>
]]></description>
</item>
</channel>
</rss>
