Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dhallによるリッチな設定ファイル体験

C468e05d33cced21afcfe2faa69828c1?s=47 syocy
June 29, 2018

 Dhallによるリッチな設定ファイル体験

LT in Japanese about dhall-lang

C468e05d33cced21afcfe2faa69828c1?s=128

syocy

June 29, 2018
Tweet

Transcript

  1. Dhallによるリッチな設定ファイル体験 @syocy 2018-06-29

  2. 設定ファイル書いてますか? 最初は小さく単純な JSON/YAML から始まるが…… ソフトウェアの成長に伴って役割が増えていく 気づくと数百行の JSON ができていたり 後段の機能に渡すために JSON

    の文字列として JSON が入り込む 2 / 18
  3. マクロの誘惑 設定ファイルにさらなる表現力を持たせたくなって くる しかし既存の設定ファイルを大きく変えたくない 独自マクロだ! → JSON 文法が破壊され構文ハイライト等が効かなく なる →実行時でないとどういう設定になるか分からなくなる

    →表現力を上げすぎると無限ループのおそれもある 3 / 18
  4. Dhall

  5. Dhall? You can think of Dhall as: JSON + functions

    + types + imports – GitHub - dhall-lang/dhall-lang Dhall とは データ表現に、 プログラマブルさと、 静的検査と、 外部ファイルのインポートを加えたもの 5 / 18
  6. Dhallはチューリング完全ではない 具体的にはループがない どうやっても無限ループしないので安心 (個人的には) 設定記述にはループがない方が読みやす い気がする ユニットテストにはあまりループを書くべきでないと いうのと近い 6 /

    18
  7. 例: Kubernetes(オリジナルYAML) 1 kind: Service 2 apiVersion: v1 3 metadata:

    4 name: my-service 5 spec: 6 selector: 7 app: MyApp 8 ports: 9 - protocol: TCP 10 port: 80 11 targetPort: 9376 (https://kubernetes.io/docs/concepts/ services-networking/service/) 7 / 18
  8. 例: Kubernetes(型注釈なしDhall) 1 { kind = 2 "Service" 3 ,

    apiVersion = 4 "v1" 5 , metadata = 6 { name = "my-service" } 7 , spec = 8 { selector = 9 { app = "MyApp" } 10 , ports = 11 [ { protocol = "TCP", port = 80, targetPort = 9376 } ] 12 } 13 } 8 / 18
  9. DhallをYAMLに変換 > cat service.dhall | dhall-to-yaml apiVersion: v1 kind: Service

    spec: selector: app: MyApp ports: - targetPort: 9376 protocol: TCP port: 80 metadata: name: my-service できたけど、これだけだと嬉しさが少ない “Service” などを typo してもエラーにならない 9 / 18
  10. Dhallの機能を活用する Dhall の機能によって静的検査を導入してみる つまり、Dhall で Kubernetes のスキーマを記述する スキーマは k8s_types.dhall という名前で別ファ

    イルに切り出す 以下の便利な標準関数を使う constructors: Union 型のコンストラクタを生成する merge: Union 型の値を任意の型に変換する 10 / 18
  11. 例: Kubernetes(Dhall色々定義1/2) 1 let Kind_ = < Service : {}

    | Pod : {} | Deployment : {} > 2 3 in let kindHandlers = 4 { Service = 5 λ(_ : {}) → "Service" 6 , Pod = 7 λ(_ : {}) → "Pod" 8 , Deployment = 9 λ(_ : {}) → "Deployment" 10 } 11 12 in let ApiVersion = < v1 : {} > 13 14 in let apiVersionHandlers = { v1 = λ(_ : {}) → "v1" } 15 16 in let Metadata : Type = { name : Text } 17 18 in let Selector : Type = { app : Text } 19 20 in let Protocol = < TCP : {} | UDP : {} > 21 22 in let protocolHandlers = { TCP = λ(_ : {}) → "TCP", UDP = λ(_ : { (次のページに続く) 11 / 18
  12. 例: Kubernetes(Dhall色々定義2/2) 24 in let Port : Type = {

    protocol : Text, port : Integer, targetPort : 25 26 in let Spec : Type = { selector : Selector, ports : List Port } 27 28 in let Yaml 29 : Type 30 = { kind : Text, apiVersion : Text, metadata : Metadata, spec 31 32 in { Kinds = 33 constructors Kind_ 34 , kind = 35 λ(k : Kind_) → merge kindHandlers k 36 , ApiVersions = 37 constructors ApiVersion 38 , apiVersion = 39 λ(v : ApiVersion) → merge apiVersionHandlers v 40 , Protocols = 41 constructors Protocol 42 , protocol = 43 λ(p : Protocol) → merge protocolHandlers p 44 , Yaml = 45 Yaml 46 } 12 / 18
  13. 例: Kubernetes(Dhall版Ver.2) 1 let types = ./k8s_types.dhall 2 3 in

    ( { kind = 4 types.kind (types.Kinds.Service {=}) 5 , apiVersion = 6 types.apiVersion (types.ApiVersions.v1 {=}) 7 , metadata = 8 { name = "my-service" } 9 , spec = 10 { selector = 11 { app = "MyApp" } 12 , ports = 13 [ { protocol = 14 types.protocol (types.Protocols.TCP {=}) 15 , port = 16 80 17 , targetPort = 18 9376 19 } 20 ] 21 } 22 } 23 : types.Yaml 24 ) 13 / 18
  14. DhallをYAMLに変換(Ver.2) > cat service_typed.dhall | dhall-to-yaml apiVersion: v1 kind: Service

    spec: selector: app: MyApp ports: - targetPort: 9376 protocol: TCP port: 80 metadata: name: my-service 結果を変えずに静的検査・関数・インポートが追加で きた! 14 / 18
  15. Dhallのツールチェイン dhall コマンド Dhall のインタプリタ。ターミナル上で Dhall ファイル のチェックをするならこれ dhall-format コマンド

    Dhall の公式フォーマッタ。保存時に自動で走るように しておくと良い (Emacs の dhall-mode は勝手にそうして くれる) 15 / 18
  16. Dhallのアプリケーション dhall-json dhall-to-json, dhall-to-yaml コマンドを提供 Dhall ファイルを JSON/YAML に変換する すでに

    JSON/YAML を使うアプリがあるなら、これを 使って静的検査と関数とインポートのある Dhall から JSON/YAML を生成しよう dhall-to-cabal Dhall ファイルを cabal ファイルに変換する Dhall を本格利用するならノウハウの宝庫なので、cabal に興味がない場合でも参考にするとよい 16 / 18
  17. バインディング プログラミング言語から Dhall を読む場合は各言語のバ インディングを利用する すでに提供されている: Haskell, Nix1 開発中: Scala,

    Rust 1正確にはプログラミング言語ではない 17 / 18
  18. 事例紹介 18 / 18