Hello Dhall(初めてのDhall)

こんにちは　こんばんは

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

# Dhallってなに？？
そもそもDhallってなんぞやと思う方がけっこういらっしゃると思います。
読み方すら自分は怪しかったです。(ダール？)
実際は「ドール」と読むそうです。

ちょーざっくりDhallを説明すると、 
`設定ファイル(yamlとかjsonとか)をプログラマブルに書く`
為の物です。

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

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

設定ファイルを書くための言語であり、これはチューリング完全ではない
と説明されています。

`チューリング完全`とは・・・・
Dhallは設定ファイルを書くためだけの、言語なので`再帰や無限ループを書けない`。
別のプログラミング言語の様に汎用性がない。と考えていただければ問題ないと思います。

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

もう少し詳しく知りたい方は[こちら](https://github.com/dhall-lang/dhall-lang)

では実際にDhallを触っていきましょう。
# Dhall を導入する

Nixで導入が可能です。(Nixを入れていない方は、[こちら](https://nixos.org/nix/))

```shell

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

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

```shell

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

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

```shell:Mac
$ brew install dhall-json
```

# Dhallに触れてみる
以下のコマンドでREPL(対話型評価環境)を起動することができる。
※以下は`dhall-json`を入れただけでは動作しません
 nix-shellにてdhallコマンド導入をお願いします。不要の方は読み流してください。

```shell

$ dhall repl
```

```dhall:dhall

⊢ 1 + 1
2
```

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

```dhall:dhall

⊢　:t 1

Natural

⊢　:t "dhall"

Text

⊢ :t True

Bool

⊢ :t [1,2,3]

List Natural
```

他にも利用できる型はあるが、ここでは割愛する。
更に詳しい詳細は[こちら](https://hackage.haskell.org/package/dhall-1.18.0/docs/Dhall-Tutorial.html#g:2)

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

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

∀(n : Natural) → Natural
```
引数の型注釈は必須となっています。

#Dhallを使って簡単なJSONを生成する
早速以下のようにDhallを使ってJSONを生成してみましょう。

```shell:shell
$ dhall-to-json <<< '{foo = [1,2,3], bar = True}'
{"foo":[1,2,3],"bar":true}
```

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

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

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

```shell: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:example.dhall
{ foo = True
, bar = [1, 2, 3, 4, 5]
, baz = "ABC"
}
```

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

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

```json:json
[
  {
    "bar": [
      1,
      2,
      3,
      4,
      5
    ],
    "baz": "ABC",
    "foo": true
  },
  {
    "bar": [
      1,
      2,
      3,
      4,
      5
    ],
    "baz": "ABC",
    "foo": true
  }
]
```
簡単に長いコードを一つのJSONとして扱えるようになりました。
この様にして、大きなJSONファイルも分割して管理することができます。（すご便利）

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

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

Error: List elements should all have the same type

- Natural
+ Bool


True

(stdin):1:4
```

これはリスト要素の中の型が不一致の為エラーとなってしまいます。
リスト要素の中はすべて同じ型である必要があります。

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

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

ここまでが、単純なJSONの作り方となります。
続いてDhallを利用して型チェックできるようにしましょう。

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

```shell:shell
$ dhall-to-json <<< '{foo = 1,bar = "True"}:{foo:Natural,bar:Text}'
```
式がスキーマ（型アノテーション）と一致しない場合、検証に失敗します（つまり、型エラーが発生する）

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

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

Error: Expression doesn't match annotation

{ bar : - Text
        + Bool
, …
}
```

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

```shell:shell
$ echo '{foo：Natural,bar：Bool}' > schema.dhall
$ dhall-to-json <<< '{foo = 1,bar = True}：./schema.dhall'
```

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

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

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

```dhall: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:shell
$ dhall-to-json --pretty <<< './emp.dhall' 
```
```json: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