🚬

10Q6 〜あるいは TypeScript で Either を do する〜

に公開

駅前の喫煙所で、僕は足を止めた。

雨上がりのアスファルトが、街灯の光をぼんやりと反射している。
誰かが吸い終えたばかりの煙草の煙が、夜の冷たい空気に溶けていくのが見えた。

僕は自分のポケットに手を入れた。
それがどういう意味を持つのか、まだ考えないままに。

「そういえば、僕は3年前に禁煙したんだった。」

1096日。
僕は煙草を吸わずに生きてきた。
それは誇るべきことのように思えたし、そうでもないようにも思えた。

彼女のことを思い出した。

彼女は、僕が最後に煙草に火をつけた夜にいた。
そして、それが僕が彼女を最後に見た夜だった。

僕にとってのレゾンデートルとは何だったのだろうか。

彼女の存在があったから僕は禁煙を選んだのか、
僕が禁煙を選んだから彼女の存在が確かだったのか。

TypeScriptの世界にも、こんなふうに 世界に委ねられた選択 を扱う仕組みがある。
それが、F-BoxEither だ。

Eitherという選択

現実の世界では、僕たちはしばしば次のような状況に出会う。

function getCigarette(): string {
  if (Math.random() > 0.5) {
    return "ラッキーストライク";
  }
  throw new Error("タバコはなかった。");
}

煙草があるかどうか、それはただの確率の問題ではない。
取り出そうとしたときに 「世界がそれを許すかどうか」 という問題だ。

もし煙草がポケットに残っていれば、
僕は Zippo に火をつけることができるだろう。

しかし、もしなければ――
それは単に「ない」というだけではなく、
僕はもう煙草を持つべきではない、という世界の意志なのかもしれない。

それなら Either を使うのが適切だ。
煙草があれば、Right
もしなければ、それは Left であり、
単なる「不在」ではなく 「世界に拒絶されるという事象」 なのだと考えられる。

例えば、ポケットに煙草があるかどうかを Either で表現すると、こうなる。

import { Either } from "f-box-core";

const right = Either.right<string, string>;
const left = Either.left<string, string>;

const checkForCigarette = (): Either<string, string> =>
  Math.random() > 0.5
    ? right("ラッキーストライク")
    : left("タバコはなかった。");

僕はZippoを持っていたのだろうか?
いや、本来なら、持っているはずがないのだ。

でも、もしポケットの奥で、Zippoの冷たい金属の感触を確かめてしまったら?
僕はもう3年前の僕になってしまうのだろうか?

const checkForZippo = (): Either<string, string> =>
  Math.random() > 0.5
    ? right("Zippo")
    : left("Zippoはなかった。");

彼女は最後に、僕の指からZippoを抜き取って、テーブルの上に置いた。
それがZippoを最後に見た夜だった。

指に伝わる金属の冷たさ、オイルの匂い、キャップを開けるときの軽い抵抗――。
それは、本当にZippoなのか?
それとも、ただの記憶の残骸なのか?

彼女の指先の感触と、Zippoの感触が、どこかで重なるような気がした。

Eitherをdoする

彼女が僕の煙草の火を消したことは覚えているのに。
彼女の声が、確かに「禁煙するんだよね?」と言ったことは覚えているのに。
名前だけが、どうしても思い出せない。

僕の記憶は、本当に確かなものか?

const checkForMemory = (): Either<string, string> =>
  Math.random() > 0.5
    ? right("1096日の禁煙の記憶")
    : left("どうやら本当に禁煙していたようだった。");

駅前の喫煙所で、僕は静かに時の流れを待っていた。
夜風が吹き抜ける音に耳を澄ませながら、do という構文を使って、
Either の連鎖を処理できることを思い出す。

const checkPocket = () =>
  Either.do<string, string, string>(function* () {
    const memory = yield checkForMemory();
    const cigarette = yield checkForCigarette();
    const zippo = yield checkForZippo();
    return `僕はポケットから ${cigarette} を取り出し、${zippo} で火をつけた。煙は夜空に静かに溶け、${memory} が胸を締めつけた。`;
  });

10Q6の夜

僕は目を開けた。
駅前の喫煙所には、ぼんやりとした煙が漂っていた。
それは誰かのものかもしれないし、僕自身のものだったかもしれない。

const scene = checkPocket();
console.log(
  scene.match(
    (failure) =>
      `僕はポケットを探ったが、${failure} 今夜はただ、静かに駅前を歩き続けることにした。`,
    (success) => success
  )
);

僕は静かにポケットを探った。
もし何かがそこにあれば、僕は再び彼女の最後の夜に戻る。
もし何もなければ、僕はこのまま夜を歩き続ける。

Zippoの冷たい金属の感触が、
彼女の指先の感触と、どこかで同じものだったような気がした。

そして、夜風が僕の頬を撫でる。
1096日――僕は本当に禁煙していたのだろうか?
あるいは、最初からそんなものは存在しなかったのかもしれない。

僕の禁煙の記憶が、彼女の存在そのものだったのだとしたら?

世界はいつも、Either でできている。
吸うか、吸わないか。記憶があるか、ないか。
彼女がいたか、いなかったか。

やれやれ、
僕は、まだその答えを知らないまま、
10Q6の夜を歩き続ける。

https://www.npmjs.com/package/f-box-core

https://github.com/KentaroMorishita/f-box-core

https://f-box-docs.com

GitHubで編集を提案

Discussion