先日、Appleが設定ファイルのためのプログラミング言語「Pkl」を公開して話題になっています。そもそも、設定ファイルにどのような形式を採用するかは、アプリの使い勝手を大きく左右するものです。今回は話題の「Pkl」について紹介します。

  • Appleがオープンソースで公開した「Pkl」を使えばいろいろなデータ形式に変換して出力できる

    Appleがオープンソースで公開した「Pkl」を使えばいろいろなデータ形式に変換して出力できる

設定ファイルの重要さについて

地味にアプリの使い勝手を左右するのが「設定ファイル」です。もちろん、多くのユーザーが利用するようなアプリであれば、GUI画面を持つ親切な設定ツールも用意されていることでしょう。

しかし、多くのコマンドラインツールや、個人が開発したツールなどの設定を行うには、設定ファイルを直接書き換えることで、アプリの挙動を変えることができるのが一般的です。そのため、アプリの設定ファイルを開いてみて、そのファイル形式や設定の複雑さや幻滅することも多々あります。そのため、設定ファイルは、アプリの使い勝手に大きな影響を及ぼします。

それで、これまで設定ファイルには、INI/XML/JSON/YAMLやTOMLと、さまざまなファイル形式が利用されてきました。それぞれに、良いところがあります。以前、こちらの姉妹連載の中でも、設定ファイルについて考察しました。

Apple発のオープンソース「Pkl」の実力は?

実際にいろいろなアプリの設定ファイルを利用してみて、「もう少し何とかならないのか」と感じることがあります。編集しやすく、分かりやすく、高度なデータを表現できることが理想です。そして、さらに設定ファイルの記述ミスが容易に分かる事や設定ファイルを気持ちよく記述できると最高です。

その点で、Appleが2024年2月に公開した「Pkl」はこれまでの設定ファイルの不満点を解決するものとなっています。

  • 「Pkl」はオープンソースでGitHubにて公開されている

    「Pkl」はオープンソースでGitHubにて公開されている

「Pkl」がスゴイのは、設定ファイルに特化した言語であることです。Pklには、豊富なデータ型が用意されておりバリデーションが用意なだけでなく、汎用プログラミング言語に用意されている、条件文やクラスなどの言語機能が備わっています。

そして、Pklには、コマンドラインツール、Java/Kotlin/Swift/Go言語のためのライブラリ、そして、VSCodeやNeoVimなどのエディタのためのプラグインが提供されています。

「Pkl」をインストールしよう

PklはオープンソースとしてGitHubにて公開されています。各種OS向けのバイナリがこちらで用意されており、それをダウンロードして利用できます。

macOSやLinuxであれば、ターミナルを起動して、下記のようなコマンドを実行するだけです。Windowsの場合は、WSLなどを利用してLinux用のバイナリを利用すると良いでしょう。

例えば、AMD64搭載マシンとLinux/WSLの環境なら、下記のようなコマンドを実行します。

# 実行ファイルをダウンロード(amd64の場合)
curl -L -o pkl https://github.com/apple/pkl/releases/download/0.25.2/pkl-linux-amd64
# pklに実行権限を与える
chmod +x pkl
# 実行できるかテスト
./pkl --version

なお、コマンドの2行目のcurlコマンドでダウンロードするバイナリは、ご利用のマシンのアーキテクチャに応じて変更します。M1/M2など、Appleシリコン搭載のmacOSであれば「pkl-macos-aarch64」を指定しましょう。Intel搭載のmacOSであれば「pkl-macos-amd64」です。

「Pkl」の基本を確認しよう

まずは、「Pkl」がどんなファイル形式なのか確認してみましょう。Pklは、基本的に下記のように「キー = 値」のような書式で記述します。いろいろな設定ファイルを知っている皆さんであれば、Windowsでよく使われたINIファイル、Rustの設定ファイルでも使われているTOMLファイルなど、王道の記述方式だと感じることでしょう。

name = "Pkl: Configure your Systems in New Ways"
attendants = 100
isInteractive = true
amountLearned = 13.37

そして、「Pkl」ではもっと複雑なデータを表現できます。複数のキーをまとめてオブジェクトとして扱うことができます。これを「オブジェクト名 { キー = 値 … }」の形式で記述します。また、配列にあたるエレメントも利用できます。エレメントは「エレメント名 { 値 … }」と記述します。

以下は、複雑なデータを表現する「fruits」オブジェクトを定義する例です。

fruits {
  name = "リンゴ"
  price = 450
  area {
    prefecture = "青森"
    city = "弘前市"
  }
  keyword {
    "甘い"
    "蜜入り"
    "完熟"
  }
}

上記の例を見ていただければ分かるとおり、オブジェクトをネストして複雑なデータを表現することもできます。

Pklでは、データファイルを、JSON/XML/YAMLなどの汎用データ形式に変換することができます。上記のデータを「fruits.pkl」という名前で保存した上で、下記のコマンドを実行してみましょう。

./pkl eval -f json fruits.pkl

上記のコマンドを実行すると、JSON形式で以下のデータが表示されます。

{
  "fruits": {
    "name": "リンゴ",
    "price": 450,
    "area": {
      "prefecture": "青森",
      "city": "弘前市"
    },
    "keyword": [
      "甘い",
      "蜜入り",
      "完熟"
    ]
  }
}

「Pkl」の実力を堪能しよう

なお、ここまで見ただけでは、「Pkl」の良さが分かりづらいと思います。「Pkl」は汎用プログラミング言語のための計算や条件分岐やループ、モジュール化の機構を備えています。

以下は、一般的なプログラミング言語にある機能を利用して、基本的な数列のリストを元にして、それを2倍、3倍したリスト、また、偶数や奇数のものだけにフィルタした数列のデータを作る例です。

// 基本的な数列をListとして定義 --- (*1)
nums = List( 2, 3, 4 )

// numsを二倍にしたnums_x2を定義 --- (*2)
nums_x2 { for (i in nums) { i * 2 } }
// numsを三倍にしたnums_x3を定義 --- (*3)
nums_x3 { for (i in nums) { i * 3} }

// numsから偶数のみを抽出したnums_evenを定義 --- (*4)
nums_even {
    for (i in nums) {
        when (i % 2 == 0) { i }
    }
}
// numsから奇数のみを抽出したnums_oddを定義 --- (*5)
nums_odd {
    for (i in nums) {
        when (i % 2 == 1) { i }
    }
}

上記のコードを「calc.pkl」という名前で保存したら、Pklで実行してみましょう。

./pkl eval -f json calc.pkl

すると、JSONデータで下記のように表示されます。

{
  "nums": [
    2,
    3,
    4
  ],
  "nums_x2": [
    4,
    6,
    8
  ],
  "nums_x3": [
    6,
    9,
    12
  ],
  "nums_even": [
    2,
    4
  ],
  "nums_odd": [
    3
  ]
}

プログラムを確認してみましょう。(*1)では2,3,4を基本的な数列をListとして定義します。

そして、(*2)と(*3)では、それぞれ、(*1)で定義したnumsの要素を2倍にしたnums_x2とnums_x3を定義します。for構文を使っているので、一般的なプログラミング言語のようにも見えます。

それから、(*4)と(*5)では、numsから偶数のみを抽出したnums_evenとnums_oddを定義します。when構文は特定の条件に合致した時のみデータを返します。

PklでFizzBuzzに挑戦

それでは、本連載の恒例である、FizzBuzz問題をPklで解いてみましょう。FizzBuzz問題とは、次のようなものです。

1から100までの数を出力するプログラムを書いてください。ただし、3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」と表示してください。3と5の倍数の時は「FizzBuzz」と表示してください。

それでは、PklでFizzBuzzの結果を表示するコードを書いてみましょう。以下のようなものになります。

// 1から100の数列を作成 --- (*1)
n10 = List(0,1,2,3,4,5,6,7,8,9)
n100 {
    for (i in n10) {
        for (j in n10) {
            i * 10 + j + 1
        }
    }
}
// FizzBuzzを作成 --- (*2)
fizzbuzz {
    for (n in n100) {
        if (n % 3 == 0 && n % 5 == 0)
            "FizzBuzz"
        else if (n % 3 == 0)
            "Fizz"
        else if (n % 5 == 0)
            "Buzz"
        else n
    }
}

上記のコードを実行するには、以下のコマンドを実行します。

この記事は
Members+会員の方のみ御覧いただけます

ログイン/無料会員登録

会員サービスの詳細はこちら