Upload
blackenedgold
View
1.510
Download
1
Embed Size (px)
Citation preview
Real World OCaml読んでみた感想
Lisp Meet Up Presented by Shibuya.lisp #14κeen(@blackenedgold)
#lispmeetup2014-02-26
自己紹介
● Twitter: κeen(@blackenedgold)● Github: KeenS● ブログ: een Happy Hac ing Blogκ の κ● 東大数学科の三年生● 就活中!
● Lisp, Ruby, シェルスクリプトが好き● CIMの開発してます
話の流れ
● OCamlと周りの環境の紹介(軽く)● Real World OCamlの紹介● OCamlの機能をLisp に取り込んでみた ボツ編● OCamlの機能をLispに取り込んでみた
OCamlと周りの環境の紹介
OCamlについて名古屋の方は黙って見てて下さい
● ML方言のCamlにオブジェクト指向を加えたもの●強い静的片付け●強力な型推論●フランスのINRIA研究所で開発されている
OCamlについて名古屋の方は黙って見てて下さい
● 関数型● 値は基本変更不可● 関数はカリー化されている
サンプルコード
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
サンプルコード
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演算子
OCamlをとりまく環境● Jane Streetという金融会社が業務で使用● 標準ライブラリにツッコみどころがある
– Jane StreetのライブラリCoreで補う– 標準ライブラリを上書きしてる
● ライブラリマネージャ、バージョンマネージャ完備
● 推奨エディタがEmacs● 日本だと名古屋が拠点
Real World OCamlの紹介
Real World OCamlの紹介
● http://realworldocaml.org●ベータ版は↑から無料で読める●英語版はオライリーより$44くらい● 510p (cf. Land of Lispは480p)●著者はOMakeの開発者XenをOCamlで開発した人Jane Streetの中の人
Real Wold OCamlの紹介
● Jane StreetのCoreを前提● 言語の基礎からコンパイラプラグインまで● プログラミングの知識はあるが関数型は初めての人対象
● 一冊読めば入門からReal Worldまでいけると思います
目次● はじめに● 第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.コンパイラバックエンド:バイトコード及びネイティブコード
● 索引
目次● はじめに● 第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.コンパイラバックエンド:バイトコード及びネイティブコード
● 索引
ボツ編
モジュール分割
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
モジュール分割
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…など
モジュール分割
(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"
原案
モジュール分割
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"
原案
モジュール分割
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"
原案
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;;
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;;
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))))
local use-package
● シンボルの解決はリード時● マクロの展開はコンパイル時
local use-package
● シンボルの解決はリード時● マクロの展開はコンパイル時
オワタ\(^o^)/
local use-package
● シンボルの解決はリード時● マクロの展開はコンパイル時
オワタ\(^o^)/
ボツ
普通編
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 | []
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 | []
コンパイルエラー
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 | []
コンパイルエラー
Common Lispでやってみる
パターンマッチはoptimaがある型を(defstruct)で一々定義するのは面倒(defvariant) …的な何かを
Common Lispでやってみる
パターンマッチはoptimaがある型を(defstruct)で一々定義するのは面倒(defvariant) …的な何かを
やってみました
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 にサンプルコードあります
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)))
Common Lispでやってみた
● 型の定義● 構造体の定義● プリティプリント● コンストラクタの定義● 構造体のスロットの型制限
● optimaのパターン定義
● match節が必要十分でないときのエラー
やってること できなかったこと
|>
let (|>) data f = f data;; ● ()で囲まれてるのは中置演算子●関数適用より優先度が低い●左結合
|>
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のパイプみたいに使える!
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))
以上質問あればどうぞ