39
Real World OCaml 読んでみた感想 Lisp Meet Up Presented by Shibuya.lisp #14 κeen(@blackenedgold) #lispmeetup 2014-02-26

Real World OCamlを読んでLispと協調してみた

Embed Size (px)

Citation preview

Page 1: Real World OCamlを読んでLispと協調してみた

Real World OCaml読んでみた感想

Lisp Meet Up Presented by Shibuya.lisp #14κeen(@blackenedgold)

#lispmeetup2014-02-26

Page 2: Real World OCamlを読んでLispと協調してみた

自己紹介

● Twitter: κeen(@blackenedgold)● Github: KeenS● ブログ: een Happy Hac ing Blogκ の κ● 東大数学科の三年生● 就活中!

● Lisp, Ruby, シェルスクリプトが好き● CIMの開発してます

Page 3: Real World OCamlを読んでLispと協調してみた

話の流れ

● OCamlと周りの環境の紹介(軽く)● Real World OCamlの紹介● OCamlの機能をLisp に取り込んでみた ボツ編● OCamlの機能をLispに取り込んでみた

Page 4: Real World OCamlを読んでLispと協調してみた

OCamlと周りの環境の紹介

Page 5: Real World OCamlを読んでLispと協調してみた

OCamlについて名古屋の方は黙って見てて下さい

● ML方言のCamlにオブジェクト指向を加えたもの●強い静的片付け●強力な型推論●フランスのINRIA研究所で開発されている

Page 6: Real World OCamlを読んでLispと協調してみた

OCamlについて名古屋の方は黙って見てて下さい

● 関数型● 値は基本変更不可● 関数はカリー化されている

Page 7: Real World OCamlを読んでLispと協調してみた

サンプルコード

let rec quicksort = function | [] -> [] | pivot :: rest -> let is_less x = x < pivot in let left, right = List.partition is_less rest in quicksort left @ [pivot] @ quicksort right

(define quicksort (match-lambda ['() '()] [(cons pivot rest) (let ([lessp (lambda (x) (< x pivot))]) (let-values ([(left right) (partition lessp rest)])

(append (quicksort left) (list pivot) (quicksort right))))]))

OCaml

Racket

Page 8: Real World OCamlを読んでLispと協調してみた

サンプルコード

let rec quicksort = function | [] -> [] | pivot :: rest -> let is_less x = x < pivot in let left, right = List.partition is_less rest in quicksort left @ [pivot] @ quicksort right

(define quicksort (match-lambda ['() '()] [(cons pivot rest) (let ([lessp (lambda (x) (< x pivot))]) (let-values ([(left right) (partition lessp rest)])

(append (quicksort left) (list pivot) (quicksort right))))]))

OCaml

Racket

再帰関数定義

リストリテラル

コンス演算子によるマッチング

ローカル関数定義

モジュール関数呼び出しタプルリテタルによる変数の分配束縛

append演算子

Page 9: Real World OCamlを読んでLispと協調してみた

OCamlをとりまく環境● Jane Streetという金融会社が業務で使用● 標準ライブラリにツッコみどころがある

– Jane StreetのライブラリCoreで補う– 標準ライブラリを上書きしてる

● ライブラリマネージャ、バージョンマネージャ完備

● 推奨エディタがEmacs● 日本だと名古屋が拠点

Page 10: Real World OCamlを読んでLispと協調してみた

Real World OCamlの紹介

Page 11: Real World OCamlを読んでLispと協調してみた

Real World OCamlの紹介

● http://realworldocaml.org●ベータ版は↑から無料で読める●英語版はオライリーより$44くらい● 510p (cf. Land of Lispは480p)●著者はOMakeの開発者XenをOCamlで開発した人Jane Streetの中の人

Page 12: Real World OCamlを読んでLispと協調してみた

Real Wold OCamlの紹介

● Jane StreetのCoreを前提● 言語の基礎からコンパイラプラグインまで● プログラミングの知識はあるが関数型は初めての人対象

● 一冊読めば入門からReal Worldまでいけると思います

Page 13: Real World OCamlを読んでLispと協調してみた

目次● はじめに● 第1 部 言語の概念

1.ひとめぐり2.変数と関数3.リストとパターン4.ファイル、モジュール、プログラム5.レコード6.バリアント7.エラーハンドリング8.命令型プログラミング9.ファンクタ10.第一級モジュール11.オブジェクト12.クラス

● 第2部 ツール及びテクニック13.マップ及びハッシュテーブル14.コマンドラインのパース15.JSONデータの扱い16.OCamllex及びMenhirによるパース17.S式によるデータシリアライゼーション18.Asyncによる並行プログラミング

● 第3部 ランタイムシステム19.外部関数の呼出し(FFI)

20.値のメモリ表現21.ガーベジコレクタを理解する22.コンパイラフロントエンド:パース及び型チェック23.コンパイラバックエンド:バイトコード及びネイティブコード

● 索引

Page 14: Real World OCamlを読んでLispと協調してみた

目次● はじめに● 第1 部 言語の概念

1.ひとめぐり2.変数と関数3.リストとパターン4.ファイル、モジュール、プログラム5.レコード6.バリアント7.エラーハンドリング8.命令型プログラミング9.ファンクタ10.第一級モジュール11.オブジェクト12.クラス

● 第2部 ツール及びテクニック13.マップ及びハッシュテーブル14.コマンドラインのパース15.JSONデータの扱い16.OCamllex及びMenhirによるパース17.S式によるデータシリアライゼーション18.Asyncによる並行プログラミング

● 第3部 ランタイムシステム19.外部関数の呼出し(FFI)

20.値のメモリ表現21.ガーベジコレクタを理解する22.コンパイラフロントエンド:パース及び型チェック23.コンパイラバックエンド:バイトコード及びネイティブコード

● 索引

Page 15: Real World OCamlを読んでLispと協調してみた

ボツ編

Page 16: Real World OCamlを読んでLispと協調してみた

モジュール分割

let rec quicksort = function | [] -> [] | pivot :: rest -> let is_less x = x < pivot in let left, right = List.partition is_less rest in quicksort left @ [pivot] @ quicksort right

Page 17: Real World OCamlを読んでLispと協調してみた

モジュール分割

let rec quicksort = function | [] -> [] | pivot :: rest -> let is_less x = x < pivot in let left, right = List.partition is_less rest in quicksort left @ [pivot] @ quicksort right

List.mapArray.mapString.map…など

Page 18: Real World OCamlを読んでLispと協調してみた

モジュール分割

(list:map #'1+ '(1 2 3)) ;=> (1 2 3)(vector:map #'1+ #(1 2 3)) ;=> #(2 3 4)(string:map (lambda (x) (code-char (1+(char-code x))))

"abc");=> "bcd"

原案

Page 19: Real World OCamlを読んでLispと協調してみた

モジュール分割

CLer「名前空間は機能を分割するためのもので型をディスパッチするものではない」CLer「ハンガリアン記法で区別可能。よって却下」

(list:map #'1+ '(1 2 3)) ;=> (1 2 3)(vector:map #'1+ #(1 2 3)) ;=> #(2 3 4)(string:map (lambda (x) (code-char (1+(char-code x))))

"abc");=> "bcd"

原案

Page 20: Real World OCamlを読んでLispと協調してみた

モジュール分割

CLer「名前空間は機能を分割するためのもので型をディスパッチするものではない」CLer「ハンガリアン記法で区別可能。よって却下」

ボツ

(list:map #'1+ '(1 2 3)) ;=> (1 2 3)(vector:map #'1+ #(1 2 3)) ;=> #(2 3 4)(string:map (lambda (x) (code-char (1+(char-code x))))

"abc");=> "bcd"

原案

Page 21: Real World OCamlを読んでLispと協調してみた

local use-package

let average x y = let open Int64 in x + y / of_int 2;;

open Int64;;let average x y = x + y / of_int 2;;

let average x y = x Int64.(+) y Int64.(/) Int64.of_int 2;;

let average x y = let module I = Int64 in x I.(+) y I.(/) I.of_int 2;;

Page 22: Real World OCamlを読んでLispと協調してみた

local use-package

let average x y = let open Int64 in x + y / of_int 2;;

open Int64;;let average x y = x + y / of_int 2;;

let average x y = x Int64.(+) y Int64.(/) Int64.of_int 2;;

(use-package :int64)(defun average (x y) (/ (+ x y) (of-int 2)))

(defun average (x y) (int64:/ (int64:+ x y) (int64:of-int 2)))

let average x y = let module I = Int64 in x I.(+) y I.(/) I.of_int 2;;

Page 23: Real World OCamlを読んでLispと協調してみた

local use-package

let average x y = let module I = Int64 in x I.(+) y I.(/) I.of_int 2;;

let average x y = let open Int64 in x + y / of_int 2;;

open Int64;;let average x y = x + y / of_int 2;;

let average x y = x Int64.(+) y Int64.(/) Int64.of_int 2;;

(use-package :int64)(defun average (x y) (/ (+ x y) (of-int 2)))

(defun average (x y) (int64:/ (int64:+ x y) (int64:of-int 2)))

(defun average (x y) (with-use-packages (:int64) (/ (+ x y) (of-int 2))))

(defun average (x y) (with-package-nicknames ((i int64)) (i:/ (i:+ x y) (i:of-int 2))))

Page 24: Real World OCamlを読んでLispと協調してみた

local use-package

● シンボルの解決はリード時● マクロの展開はコンパイル時

Page 25: Real World OCamlを読んでLispと協調してみた

local use-package

● シンボルの解決はリード時● マクロの展開はコンパイル時

オワタ\(^o^)/

Page 26: Real World OCamlを読んでLispと協調してみた

local use-package

● シンボルの解決はリード時● マクロの展開はコンパイル時

オワタ\(^o^)/

ボツ

Page 27: Real World OCamlを読んでLispと協調してみた

普通編

Page 28: Real World OCamlを読んでLispと協調してみた

Variantとパターンマッチlet rec quicksort = function | [] -> [] | pivot :: rest -> let is_less x = x < pivot in let left, right = List.partition is_less rest in quicksort left @ [pivot] @ quicksort right

type 'a list = 'a :: 'a list | []

Page 29: Real World OCamlを読んでLispと協調してみた

Variantとパターンマッチlet rec quicksort = function | [] -> [] | pivot :: rest -> let is_less x = x < pivot in let left, right = List.partition is_less rest in quicksort left @ [pivot] @ quicksort right

type 'a list = 'a :: 'a list | []

コンパイルエラー

Page 30: Real World OCamlを読んでLispと協調してみた

Variantとパターンマッチlet rec quicksort = function | left , right -> left :: [right] | [] -> [] | pivot :: rest -> let is_less x = x < pivot in let left, right = List.partition is_less rest in quicksort left @ [pivot] @ quicksort right

type 'a list = 'a :: 'a list | []

コンパイルエラー

Page 31: Real World OCamlを読んでLispと協調してみた

Common Lispでやってみる

パターンマッチはoptimaがある型を(defstruct)で一々定義するのは面倒(defvariant) …的な何かを

Page 32: Real World OCamlを読んでLispと協調してみた

Common Lispでやってみる

パターンマッチはoptimaがある型を(defstruct)で一々定義するのは面倒(defvariant) …的な何かを

やってみました

Page 33: Real World OCamlを読んでLispと協調してみた

Common Lispでやってみた

(defvariant tree leaf (red tree t tree) (black tree t tree))

type 'a tree = | Leaf | Red of tree * 'a * tree | Black of tree * 'a * tree

赤黒木の例

gist https://gist.github.com/9225141 にサンプルコードあります

Page 34: Real World OCamlを読んでLispと協調してみた

Common Lispでやってみた

(defvariant tree leaf (red tree t tree) (black tree t tree))

type 'a tree = | Leaf | Red of tree * 'a * tree | Black of tree * 'a * tree

赤黒木の例

gist https://gist.github.com/9225141 にサンプルコードあります

(PROGN (DEFTYPE TREE () '(OR (MEMBER LEAF) BLACK RED)) (DEFSTRUCT (BLACK (:CONSTRUCTOR BLACK (#:TREE1014 #:T1015 #:TREE1016)) (:PRINT-OBJECT (LAMBDA (OBJ STREAM) (FORMAT STREAM "(~a ~{~a~^ ~})" 'BLACK (LIST-SLOTS OBJ '(#:TREE1014 #:T1015 #:TREE1016) (FORMAT NIL "~a-" 'BLACK)))))) (#:TREE1014 NIL :TYPE TREE) (#:T1015 NIL :TYPE T) (#:TREE1016 NIL :TYPE TREE)) (DEFPATTERN BLACK (#:TREE1014 #:T1015 #:TREE1016) (LIST 'BLACK- :TREE1014 #:TREE1014 :T1015 #:T1015 :TREE1016 #:TREE1016)) (DEFSTRUCT (RED (:CONSTRUCTOR RED (#:TREE1017 #:T1018 #:TREE1019)) (:PRINT-OBJECT (LAMBDA (OBJ STREAM) (FORMAT STREAM "(~a ~{~a~^ ~})" 'RED (LIST-SLOTS OBJ '(#:TREE1017 #:T1018 #:TREE1019) (FORMAT NIL "~a-" 'RED)))))) (#:TREE1017 NIL :TYPE TREE) (#:T1018 NIL :TYPE T) (#:TREE1019 NIL :TYPE TREE)) (DEFPATTERN RED (#:TREE1017 #:T1018 #:TREE1019) (LIST 'RED- :TREE1017 #:TREE1017 :T1018 #:T1018 :TREE1019 #:TREE1019)))

Page 35: Real World OCamlを読んでLispと協調してみた

Common Lispでやってみた

● 型の定義● 構造体の定義● プリティプリント● コンストラクタの定義● 構造体のスロットの型制限

● optimaのパターン定義

● match節が必要十分でないときのエラー

やってること できなかったこと

Page 36: Real World OCamlを読んでLispと協調してみた

|>

let (|>) data f = f data;; ● ()で囲まれてるのは中置演算子●関数適用より優先度が低い●左結合

Page 37: Real World OCamlを読んでLispと協調してみた

|>

let (|>) data f = f data;; ● ()で囲まれてるのは中置演算子●関数適用より優先度が低い●左結合

# String.split ~on:':' "/usr/bin:/usr/local/bin:/bin:/sbin" |> List.dedup ~compare:String.compare |> List.iter ~f:print_endline ;;/bin/sbin/usr/bin/usr/local/bin

unixのパイプみたいに使える!

Page 38: Real World OCamlを読んでLispと協調してみた

Lispでやってみた

Clojure->>があるCommon Lisp(defmacro ->> (data &rest funs) (reduce (lambda (x y)

`(funcall ,y ,x)) funs :initial-value data))

Scheme(define (->> data . funs) (fold (lambda (x y) (x y)) data funs))

Page 39: Real World OCamlを読んでLispと協調してみた

以上質問あればどうぞ