Edited at
UUUMDay 13

Hello Dhall(初めてのDhall)

こんにちは こんばんは

kenjiです。

今回はDhall言語について書きたいと思います。(AWSについてばっかだったので)


Dhallってなに??

そもそもDhallってなんぞやと思う方がけっこういらっしゃると思います。

読み方すら自分は怪しかったです。(ダール?)

実際は「ドール」と読むそうです。

ちょーざっくりDhallを説明すると、

設定ファイル(yamlとかjsonとか)をプログラマブルに書く

為の物です。

公式には以下のような記述がされております。

Dhall is a programmable configuration language that is not Turing-complete

設定ファイルを書くための言語であり、これはチューリング完全ではない

と説明されています。

チューリング完全とは・・・・

Dhallは設定ファイルを書くためだけの、言語なので再帰や無限ループを書けない

別のプログラミング言語の様に汎用性がない。と考えていただければ問題ないと思います。

もう一度いいます、これは設定ファイルを書く為だけの言語です

もう少し詳しく知りたい方はこちら

では実際にDhallを触っていきましょう。


Dhall を導入する

Nixで導入が可能です。(Nixを入れていない方は、こちら)


$ nix-shell -p dhall dhall-json
$ dhall version

導入がめんどくさい方/お試し実施したい方


$ docker pull nixos/nix
$ docker run -it nixos/nix
[id]:/# nix-shell -p dhall dhall-json
[id]:/# dhall version

今回はdhall-jsonを利用してJSONを作成するので、Macの方は以下でもOK


Mac

$ brew install dhall-json



Dhallに触れてみる

以下のコマンドでREPL(対話型評価環境)を起動することができる。

※以下はdhall-jsonを入れただけでは動作しません

nix-shellにてdhallコマンド導入をお願いします。不要の方は読み流してください。


$ dhall repl


dhall


⊢ 1 + 1
2

値の型を確認したい場合は以下のように:tが利用できる


dhall


⊢ :t 1

Natural

⊢ :t "dhall"

Text

⊢ :t True

Bool

⊢ :t [1,2,3]

List Natural


他にも利用できる型はあるが、ここでは割愛する。

更に詳しい詳細はこちら

もちろん以下のような関数を定義することもできる。


dhall

:t λ(n : Natural) -> n * 2

∀(n : Natural) → Natural


引数の型注釈は必須となっています。


Dhallを使って簡単なJSONを生成する

早速以下のようにDhallを使ってJSONを生成してみましょう。


shell

$ dhall-to-json <<< '{foo = [1,2,3], bar = True}'

{"foo":[1,2,3],"bar":true}

以下の方法でも同一の結果を得ることができる。


shell

$ echo  '{foo = [1,2,3],bar = True}' | dhall-to-json

{"foo":[1,2,3],"bar":true}


キレイな形でJSONを出力する

以下のように--prettyオプションをつけることによって、整形されたJSONが出力できる。


shell

$ echo  '{foo = [1,2,3],bar = True}' | dhall-to-json --pretty

{
"bar": true,
"foo": [
1,
2,
3
]
}


どうでしょう? 簡単に生成できましたね。

このぐらい短いコードなら上記のようにコマンドラインで実装できると思いますが、

コードが長くなった場合コマンドライン上で実装するのは難しくなってきます。

ではどうするか

以下のコードをファイルに保存しましょう。

{ foo = True, bar = [1, 2, 3, 4, 5], baz = "ABC"}


example.dhall

{ foo = True

, bar = [1, 2, 3, 4, 5]
, baz = "ABC"
}

以下のコマンドを実施してみましょう。


shell

dhall-to-json --pretty <<< '[ ./example.dhall, ./example.dhall ]'



json

[

{
"bar": [
1,
2,
3,
4,
5
],
"baz": "ABC",
"foo": true
},
{
"bar": [
1,
2,
3,
4,
5
],
"baz": "ABC",
"foo": true
}
]

簡単に長いコードを一つのJSONとして扱えるようになりました。

この様にして、大きなJSONファイルも分割して管理することができます。(すご便利)

一つ注意として以下の書き方になると、エラーとなります。


shell

$ dhall-to-json <<<  '[1,True]'

Error: List elements should all have the same type

- Natural
+ Bool

True

(stdin):1:4


これはリスト要素の中の型が不一致の為エラーとなってしまいます。

リスト要素の中はすべて同じ型である必要があります。

細かいエラー内容を必要とする場合は--explainオプションを入れください。


shell

$ dhall-to-json --explain <<<  '[1,"True"]'


ここまでが、単純なJSONの作り方となります。

続いてDhallを利用して型チェックできるようにしましょう。


型チェックをする

型チェック検証をやってみましょう。


shell

$ dhall-to-json <<< '{foo = 1,bar = "True"}:{foo:Natural,bar:Text}'


式がスキーマ(型アノテーション)と一致しない場合、検証に失敗します(つまり、型エラーが発生する)

例えば以下のような形です。


shell

$ dhall-to-json <<< '{foo = 1,bar = True}:{foo:Natural,bar:Text}'

Error: Expression doesn't match annotation

{ bar : - Text
+ Bool
, …
}


型注釈を含むファイルをインポートすることもできます。


shell

$ echo '{foo:Natural,bar:Bool}' > schema.dhall

$ dhall-to-json <<< '{foo = 1,bar = True}:./schema.dhall'


let式

let式を利用し、複数回参照できる変数を定義することができます。


shell

$ dhall-to-json <<< 'let x = [1, 2, 3] in [x, x, x]'

[[1,2,3],[1,2,3],[1,2,3]]

このlet式を利用して以下の様にJSONを生成することができます。


emp.dhall

    let job = { department = "Data Platform", title = "Software Engineer" }           

in let john = { age = 23, name = "John Doe", position = job }

in let alice = { age = 24, name = "Alice Smith", position = job }

in [ john, alice ]



shell

$ dhall-to-json --pretty <<< './emp.dhall' 



json

[

{
"age": 23,
"name": "John Doe",
"position": {
"department": "Data Platform",
"title": "Software Engineer"
}
},
{
"age": 24,
"name": "Alice Smith",
"position": {
"department": "Data Platform",
"title": "Software Engineer"
}
}
]

如何でしょう。

この様にして、大きなJSONファイルを分割して管理したり、型チェックをしたり等

今まで設定ファイルでは叶えることができなかった部分をプログラマブルに書くことができないだろうか。

今回はJSONを紹介したが、もちろんyaml shellもサポートされている。

次回はこれでdocker-compose.ymlを生成していきたい。


参考にさせていただいたサイト

https://ryota-ka.hatenablog.com/entry/2018/08/27/110000

https://github.com/dhall-lang/dhall-lang/wiki/Getting-started%3A-Generate-JSON-or-YAML