0Pricing
TypeScript Academy · レッスン

パーサーコンビネーターの概念

小さなパーサーを組み合わせて、より大きなパーサーを構築します。

「パーサーコンビネーターの概念」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。

パーサーとは

パーサーは入力(通常は文字列)を読み取り、構造化された出力を生成するか、失敗します。まずは値のレベルから始めて直感を養い、その後で同じ考え方を型システムに移します。

type Parser<T> = (input: string) => { value: T; rest: string } | null;
// Consumes part of the input, returns a value and the leftover

小さなパーサー

最も単純なパーサーは、リテラルのプレフィックスに一致するかを調べます。入力が期待するテキストで始まっていれば成功し、残りの文字列を返します。そうでなければnullを返します。

function literal(prefix: string): Parser<string> {
  return input =>
    input.startsWith(prefix)
      ? { value: prefix, rest: input.slice(prefix.length) }
      : null;
}
console.log(literal("ab")("abc"));

コンビネーター

コンビネーターは小さなパーサーを受け取り、より大きなパーサーを構築します。このように組み合わせていくスタイルが、単純で再利用可能な部品から複雑なパーサーを組み立てる手法をパーサーコンビネーターと呼ぶ理由です。

// Small parsers: digit, letter, literal
// Combinators: sequence, choice, many
// Compose them into: number, identifier, expression

逐次実行

シーケンスコンビネーターは、まず1つ目のパーサーを実行し、残りの入力に対して次のパーサーを実行して、結果を組にします。シーケンスが成功するには、両方が成功しなければなりません。

function seq<A, B>(pa: Parser<A>, pb: Parser<B>): Parser<[A, B]> {
  return input => {
    const ra = pa(input);
    if (!ra) return null;
    const rb = pb(ra.rest);
    if (!rb) return null;
    return { value: [ra.value, rb.value], rest: rb.rest };
  };
}

順序の使用

2つのリテラルを組み合わせて、順番に解析します。結果には、一致した両方の部分と残りの入力が含まれます。

const ab = seq(literal("a"), literal("b"));
const r = ab("abc");
console.log(r); // { value: ["a","b"], rest: "c" }

選択

選択コンビネータは最初のパーサーを試し、失敗した場合は2番目のパーサーを試します。これは「数字または文字」のような選択肢を表します。

function alt<T>(p1: Parser<T>, p2: Parser<T>): Parser<T> {
  return input => p1(input) ?? p2(input);
}

繰り返し

many コンビネータは、失敗するまでパーサーを繰り返し適用し、すべての結果を収集します。これにより、リストや数字の連続、空白を解析できます。

function many<T>(p: Parser<T>): Parser<T[]> {
  return input => {
    const out: T[] = [];
    let rest = input;
    let r = p(rest);
    while (r) { out.push(r.value); rest = r.rest; r = p(rest); }
    return { value: out, rest };
  };
}

結果の変換

map コンビネータは、消費する入力を変えずにパーサーの結果を変換します。たとえば、一致した数字文字を数値に変換できます。

function map<A, B>(p: Parser<A>, f: (a: A) => B): Parser<B> {
  return input => {
    const r = p(input);
    return r ? { value: f(r.value), rest: r.rest } : null;
  };
}

組み立てる

これらの少数のコンビネータ(literal、seq、alt、many、map)から、数値や識別子、さらには小規模な式言語まで、実際の文法を解析できます。各層は、その下の層を組み合わせて構成されます。

const digit = alt(literal("0"), literal("1")); // toy digit
const digits = many(digit);
console.log(digits("0110x"));

値から型へ

重要な洞察は、同じ合成構造が型レベルでも機能することです。型レベルでは、「入力」は文字列リテラル型であり、パーサーはテンプレートリテラル推論を使う条件型です。次は型レベルへ進みます。

// Value level: (input: string) => { value, rest } | null
// Type level:  conditional types over string literal types

なぜ型レベルで解析するのか

型レベルのパーサーを使うと、コンパイラーは文字列リテラルの構造を理解できます。対象には、ルートパス、フォーマット文字列、クエリキーなどがあります。ここで身に付けたコンビネータの直感は、このコースの後半で扱う型レベルのテクニックにそのまま対応します。

// Goal: parse "users/:id" into { id: string } at compile time

理解度チェック

パーサーコンビネータについての理解度を確認します。

まとめ

値レベルでパーサーの基本的な考え方を身に付けました。

  • パーサーは入力を消費し、残りの入力と値を返すか、失敗します。
  • コンビネータ(seq、alt、many、map)は、小さなパーサーを組み合わせて大きなパーサーを作ります。
  • 同じ構造を型レベルにも適用できます。

次は、型システムで文字列を分割します。

よくある質問

「パーサーコンビネーターの概念」レッスンは無料ですか?

はい。「パーサーコンビネーターの概念」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。

「パーサーコンビネーターの概念」で何を学びますか?

小さなパーサーを組み合わせて、より大きなパーサーを構築します。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

TypeScript Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「パーサーコンビネーターの概念」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このTypeScript Academyレッスンでコードを書いて実行できますか?

はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. パーサーコンビネーターの概念
  2. 型レベルの文字列分割
  3. テンプレートリテラルによる解析
  4. 型レベルのミニルートパーサー
← TypeScript Academyに戻る