• http://kokucheese.com/event/index/6300/
  • 日時: 2010年12月22日(18:00-20:00(開場17:30))
  • 開催場所: 株式会社豆蔵トレーニングルーム(新宿三井ビルディング34階) (東京都新宿区西新宿二丁目1番1号)
  • 主催: 株式会社豆蔵、有限会社ITプランニング

b95213b1.jpg新宿三井ビルに着いてエレベーターはどこだろうとうろうろしていると、あちこちにOLがしかも大量に実在している!女性専用車両並の異常現象。うちの会社は女性率が1割だし(大学は物理学科だったし)これはアリエナイ。

とか考えながらサクっと34階について会場入りする前にトイレにいくと、給湯室にもOLが屯(たむろ)してたよ。

b5940702.jpgなれない関数型言語の話ということで、途中で集中力を切らさないようにカフェインとブドウ糖を補給するためコカコーラを購入。

intro

  • 豆蔵:小林健一さん
  • 声でかっ
  • 1/31 AlloyAnalyzerセミナー(無料) をやるそう。

講師自己紹介: 小笠原啓さん

  • @osiire
  • 遍歴: Fortran→Standard ML→OCaml
  • パックマンではなくて、これは卵を2つ重ねた形。
  • 「Functional イカ娘」で検索するとでてくるでゲソ

関数型言語の歴史

  • lambda: Alonzo Church
  • LISP: John McCarthy [1927-] まだ生きてる
  • Scheme: inspired by Actors
  • standard ML(Meta Language)
  • Haskell (version1.0 1990)
    • Haskell is lazy.
    • Haskell is pure.
    • Haskell has type classes.
    • Haskell has no formal semantics.
    • Haskell is a committee language.

関数型言語とは

  • ラムダ計算を念頭において作られた言語。
  • 様々な関数型言語がある。
    • C++ const教boost派は関数型と主張してたり。

関数型言語の利欠点

  • 利点:
    • 末尾再帰最適化
    • 継続、部分継続
    • 評価戦略の意味論
    • 型付けの安全性
    • 推論の限界
    • 言語仕様でできないことには、ちゃんと理由がついてくる。
  • 欠点:
    • 副作用と戦う必要
    • 参照をいれると多相が制限される
    • 外界と交流するためにアクション
    • IO型との戦い

Microsoft Visual F#について

  • Fortranではありません!
    • なんとwikipediaに科学技術計算のための言語とかかれたことがある。
  • FはfunctionalのFだとおもう。
  • 実は2005/01にpreview reelaseされている。
  • オープンソース apache2にそっくりライセンスの microsoft research shared source license。
  • Vitual Studio Shell 2010( 2008): 言語なしのガワのみIDE
  • Microsoft F# free tools (CTP Nov, 2010)

F#の概要

  • OCamlをベースに開発。
  • 'Object'の部分がちょっとちがう。
  • Scalaに似ているが方向性がちがう:
    • scalaはオブジェクト指向がベースで関数型の拡張
    • F#は関数型がベースでオブジェクト指向の拡張
  • 開発者: Don Syme (ドン・サイム)
    • C#や.NETジェネリクス機能にたずさわっていた。

F#の特徴

  • 静的型付け関数型言語
  • 型推論 (完全ではない。書かなければならないところがある)
  • 判別共用体(←F#用語)とパターンマッチ
  • アクティブパターン: パターンマッチするときに任意の関数をはさめる
  • シーケンス式: 遅延リストの内包様式
  • 計算式(←F#用語;computational expr): いわゆるDo構文のことで 1+2 とかではない。
  • 第一級のイベント
  • 非同期/並列ライブラリ(計算式を応用したもの) 目玉機能!
  • 単位つき浮動小数点
  • コード引用符(マクロ;code quotation)
  • モジュールの容易な実装
  • .NET環境で動作 (豊富なライブラリが利用できる)
  • F#インタラクティブ (REPL) (その場で実行できる)
  • IDEによる支援
    • ないときびしい!!!
    • オフサイドルール(インデントによっていみがかわる)をおしえてくれる。縦線がはいるとか。

F#の利点

  • バグの少ないコードがかける。
  • 素早くコードがかける。 パーサーコンビネータとか

対話環境(REPL)

#;と:、[と{の区別がつきにくかったのでまちがってるかもしれない。

> 1;;  セミコロン2つでおわり。
val it : int = 1
> 1.0;;
val it : float = 1.0
> "string";;
val it : string = "string"
> 'A';;
val it : char = 'A'
> true;;
val it : bool = true
> [1;2;3];;
val it : int list = [1;2;3]
> [|1;2;3|];;
val it : int []=[|1;2;3|]
> [1..10];;
val it : int list = [ 1;2;3 …
> [ for c in [1..10] -> c];;
val it : int list = [ 1;2;3 …
> [ for c in [1..10] do yield c c];;
val it : int list = [ 1;2;3 …
> let x = 10;;
val x : int = 10
> let x;;
エラー
> (1, 2);;
val it : int * int = (1, 2)
> [ ("ogasawara", 34); (... 連想配列
> let add x = x + 1;;
val add : int -> int
> let add x y = x + y;;
val add : int -> int -> int
多重定義ではなくてシャドーイング。前の定義は隠される。
> add 3 4;;
val it : int = 7
あまりカッコをつかわない (schemerは括弧は見えないとかいうけど)
> let add2 x y =
     let add x y = x + y in
     (add x y ) + (add  x y);;
val add2 : int -> int -> int

判別共用体とパターンマッチ

> type t = ON | OFF;;
Cのenumとおなじ
> type t' = ON of int | OFF;;
onのときだけ明るさを持てるとか。
> ON 3;;
> OFF;;

optionモジュール

  • プログラミング拳固から悪魔のnullを排除しくみ
  • None or Some x
> open System;;
> Environment.GetEnvironmentVariable "home";;
val it : string = "c:\..."
> Environment.GetEnvironmentVariable "home2";;
val it : string = null
> (Environment.GetEnvironmentVariable "home2").Trim();;  Trimは余計な空白を取り除く関数
実行時エラー
> let get_safe_env str =
    match Environment.GetEnvironmentVariable str with
        null -> None
        | x -> Some x;;
val get_sfe_env : string -> string option
> (get_safe_env "home2").Trim();;
コンパイルエラー (実行時エラーではなくなった)
…このあと動くバージョンが示されるがメモれず…
  • Q: 空文字列の場合は?
  • A: get_safe_envで空文字列だったらNoneを返すようにすればよい。
  • Q: OCamlにはnullがないのにF#にあるのはなぜか?
  • A: .NETにあるのでしかたがない。それを使うため。
    • 特に3rd party物だと手がだせない。
    • ちなみにF#の標準ライブラリにはにはnullを返すやつはない。
  • Q: nullの型は?
  • A:
> null;;
val it : 'a when' a : null = null

シーケンス式

  • 遅延リストであるseq<'a>を構築する内包表記。
  • System.Collections.Generic.IEnumerableがシーケンス。頻出のテクニック。
  • unfold,map.take,reduce,append,concat,filter,exists,find.forall,iter,zip
> seq { 1..10 };;
val it : seq<int> = seq [ 1;2;3;4;...] 表現がちがう! リテラルをコピペできない。pretty printerの問題?
> seq [ for c int [ 1.. 10 ] - >c};;
> let rec再帰 listFiles basePath =
 seq {
   yield! Directory.GetFiles(basePath) バンはリストはてんかいしろのしるし
   for subdir in Directory.GetDirectories(basePath) do
     yield! listFiles subdir
 }
 ;;
  • Q: エラー処理が書いてないがどう書けばよい?
  • A: try/catchでかこんでエラーがおこったら空リストを返すようなラッパーをかけばok。

mutableキーワードがついている変数には 「<-」 は破壊的代入ができる

「|>」パイプ演算子

  • f(g(h)) みたいなのは f |> g |> h と書ける (と理解したがあってるかな)

測定単位

> [<Mesure>]
type m;; ※ふつうはtype m=...
> 1.0<m> * 2.0<m>;;
val it : float<m ^ 2> = 2.0
> [<Measure>]
type s;;
> 10.0<m> / 5.0<s>;;
val it : float<m/s> =2.0
  • 単位が合わないとエラーになる。
  • 消費税計算で内税/外税の区別でつかったことがある。
  • SI単位系が用意されている

非同期ワークフロー

  • 非同期計算を表現する計算式。
  • イベントベースではなく、逐次的な処理として表現可能。
  • 例外処理が一度に書けるのがすごい。
    • ふつうはクロージャのまわりをtry catchしても、呼出側の方でtry catchしないとダメだけど。
async { ほげ } ※asyncはキーワードではなくてインスタンス
["http://"; "http://"]
|> Listmap getHtml
|> ASync.Parallel ←ここではまだ実行は始まってない
|> Async.RunSynchronousely;; ←ここではじめて実行がはじまる

async {
  try
    ...
  catch
   e->
}
  • Q: 1つのページでもエラーになったら全部とめたいときは?
  • A: たぶん全然べつの書き方になる。

第一級のイベント

  • IOblservableインタフェース

GUIプログラムの作成

(初期画面で項目が選択されてない場合の処理が抜けていてバグる場合を例にあげて説明)

まとめ

  • 関数型言語は歴史ある言語、工学的な基礎があり、信頼にあたいします。
  • 静的型付け関数型言語であるF#は、不具合の少ないプログラムを低コストで世区政できる言語です。
  • .NET環境のライブラリを活用でき、既存のコードとの共存もできます。
    • scalaはCLIにコンパイルできるだけ。
  • プログラミング F# オライリー なかなかよい 安くかえる
  • 実線F#関数型プログラミング入門
  • web: Microsft F# Developer Center

質疑応答

  • Q: 実績
  • A: OCamlは5年前からつかっている。
  • linux daemon 24h365d うごいている。 ocaml
  • scalaもつかったことがある。初心者でもできた。
  • Q: 形式的手法への道筋
  • A: ベースが数学という観点でセミナータイトルになっている。
  • …むつかしくて理解できず…
  • Q: F#のこんぱいらはF#でかかれている?
  • A: F#のこんぱいらはF#でかかれている (全部じゃないけど)。
  • 5年前はいろいろバグはあったけど
  • いまはコンパイラのバグをふんだことはない。枯れているとおもう。
  • Q: なぜF#か?
  • A: ビジネス的に考えて、OCamlよりも.NETがつかえるF#の方が普及が早いとおもっている。F#からはいってOCamlにシフトしてゆくのもありか。


cc3f0c3f.jpgセミナー終了後、かずさんから食事にさそっていただいたので、かずさんのおしりあいの人たちと京王デパートへ。なんとなく中華の「龍鳳」へ

ふだん外ではジャンクフードしか食べないので割高な感じでサイフがとっても不安になったがここはポーカーフェイスで。

わたし以外の人は言語通のようで、話になかなかついていけず、覚えている範囲でキーワードのみメモっておく。

  • 判別共用体の話の補足
    • 戻り値にエラーがふくまれるのかどうかを型で表せるのがいい。Cだと仕様を読まないとわからない。
  • セミナーの例題に出てきたディレクトリ・トラバーサル
    • getdents()は一度にディレクトリエントリをとってきたような気がしたらしい。
    • でもふつうのunix FSだとページ単位くらいでとってきてるとおもう。
    • NFSにはcookieを指定して間欠的に取得できるようになっている。
  • GoF vs 高階関数
    • template patternとか、高階関数があればデザインパターンなんて不要らしい。
  • Haskellを数値計算屋に
    • いまどきはrubyで計算したりするらしい。性能がでるのか疑問だけど。
    • Haskellには配列はあるよ。
    • ふつう性能のことを考えて配列に破壊的代入したくなるよね。
    • クラスタ計算機で動かすにはMPIは必須。
    • 事後補足: まずはNPB(NAS PARALLEL BENCHMARKS;通称ナスパラ)が動けばアピールできるとおもう。
    • レイトレーシングの並列化は簡単な方か。
    • GPGPUもつかえるようにしたらいい。
  • box/unbox
    • boxは間接参照(化)のことらしい。
    • 整数をそのままあつかう(unbox)か、参照をとおしてつかうか(box)。
    • Javaだとintはunboxで、class Integerがbox、みたいな。
    • すなおに処理系を実装すると全部boxになるんだそう。
    • unboxとboxが混在するとタグビットが必要に。
      • intが1wordまるまる使えなくて精度が落ちるとか。
      • 2ワードにするとアトミックにコピーできなくてGCでこまるとか。
  • parsec2
    • parsecというパーサーを簡単に書けるライブラリがあるらしい。
    • おれは再帰降下でガリガリ毎回書いてるけど。
    • parsecはversion 3
    • parsec2はversion 1
    • という、なんかカオスなことになっているらしい。
    • (心の声: やっぱりはHaskell屋はあたまがおかしいのか?)
    • lexerのparsecの中で書けるらしい。(心の声: Cだったら効率を考えて分けるとおもうけども。)
    • バックトラックを止めるためにキーワードを置くらしい。
  • Haskellライブラリのバージョン依存関係
    • バージョンがどんどんあがってたいへん。
    • そんなんでバージョンの上限が指定されているものもある。(後方互換性がないってことか?)
    • build時の依存性はなんとかできるけど、実行時の依存性があって混在したら動かないよね。
  • let rec
    • いちいちrecって書くのはなぜか?
    • recと書いてないときにはコンパイラが最適化で楽をできるかららしい。
    • recがついてると、いちどグラフを展開しなければいけなくて、遅くなる。
  • perlきもい
    • 人におしえるときは @ はつかわないで [] だけをつかって書くようにしている。その方がかんたん。
    • 下手に書くと配列をコピーしまくるコードになってたり。
  • リテラルべんり。
    • あたりまえすぎき便利さに気づいてない。perlとかひどい。
    • 値をprintした結果をそのまま入力としてつかえるということ。
    • C/C++にはpretty printerがないからなぁ。
  • 正規表現のNFA→DFA
    • 正規表現にはperl派とposix派がある。が、ほとんどはperl派。
    • posixではNFAをDFAに変換するよう仕様に書いてあるらしい。
    • なんかもめてたが論点がすれちがってるのかどうかさえよくわからなかった。
    • perlの拡張があるときにどうとかこうとか。
  • 最近のC++だとコンパイル単位をまたがって定数式の伝搬ができるらしい。
  • ocamlはコンパクトなのがウリ
  • delegation
  • mutable