ようこそ。睡眠不足なプログラマのチラ裏です。

Comm Tech Festival D-3 「open FSharp」 (続きはWebで)

@ufcpp さんにお話しをいただいて Comm Tech Festival に参加してきました。ありがとうございました。 comuplus.doorkeeper.jp

「open FSharp」というタイトルで発表させていただいたのですが、時間配分がうまくいかずにスライドの最後まで紹介することができませんでした。申し訳ありません(はずかしい)。

「続きはWebで。」とお約束をしていたので、こちらにまとめます。使用したスライドをそのまま公開することも考えましたが、それだと内容が伝わりにくくてあまり価値がなさそうかなと思ったのと、変な誤解をされる恐れもあると考えたので、発表時に話した内容に簡単な補足を加えたり、ときにはざっくり省いたりしたかたちでこちらにまとめることにしました。


時間オーバーしただけあってだいぶ長いです(ポエム)。
セッションを聞いていただいたかたは、続きのみどうぞ

f:id:zecl:20150927154047j:plain
f:id:zecl:20150927154123j:plain

@mayukiさんが作ってくれた画像。あまり深くは触れませんが、IQ145 がだいぶやばいです。別に殺伐とはしていなかったはず。

f:id:zecl:20150927154337j:plain
基本的には、F#が"ふつうに関数型言語である"というありがたみのない話

f:id:zecl:20150927154435j:plain
f:id:zecl:20150927154509j:plain
言語遍歴としてはVB(レガシー的なのも含む)、C#Java、あとはDelphiあたり。その他いろいろさわってますが、よく知られている(一般的な)オブジェクト指向言語をつかって仕事をしていることが多かったです。
かつて関数型言語関連の研究をしていたとか、数学が得意だとかでもなく一般の人。

C#の会社に所属していながら、F#の話をする。どうなんだ?という感じですが、理解ある会社、同僚たちと働かせてもらえてありがたいことです。


f:id:zecl:20150927154644j:plain
弊社開発者、結構 F# インストールしてくれています。使ってくれている(or 今後使ってくれる)かどうかはわかりませんが。 こちらのツイートをみたとき、まゆきさんツンデレだなあと思いました。

f:id:zecl:20150927154943j:plain
自宅でのVSのデフォルト環境は F# にしてます(だから何)

f:id:zecl:20150927155131j:plain
・FsBulletML
むかし一世を風靡した(?)弾幕記述言語BulletML(ABA Games)のF#実装。
特徴としては、判別共用体による型付き内部DSLXML、SXML、FSB(独自形式)の3種類の外部DSLを備えていることです。
また、各外部DSLから内部DSLへのコンパイル時変換を可能とする FsBulletML.TypeProviders も提供しています。NuGetである程度DLされているんだけど、使ってみたという話を一度も聞いたことないですね。

・UniFSharp
Unityエディタ上からMSBuildを実行してF#をビルドするやつ。
疑似的にF# ScriptをインスペクターにD&Dできたりします。あと、無駄にUnityちゃんがしゃべります。Unity で F# がサポートされるようになる日は、まずこなさそうですね。

f:id:zecl:20150927155515j:plain
F#に対して「無関心」だった人に関心をもってもらいたい。F#に対してもともと「関心」があった人をより協力者に近づけたい。というのを目標(目的に)

>どうして F# を流行らせたい?
単純に良いと思うものは広めたいし。語り合える仲間が増えるのはうれしいよね!というのは当然として、ユーザーが少ないことは問題でしかないと考えるからですね。実際ユーザが少なくてイイことなどまるでないので。開発者が少ないということは、ライブラリやフレームワークの選択肢の幅も狭くなります。書籍も出版されにくいし、Web上でも情報が少なく何かトラブルがあったときに困る可能性があります。んなもんで、ビジネスにも適用されにくくなります。とかいう、ごくふつうの話

f:id:zecl:20150927160039j:plain
実はVisual Studio 2010からいました

f:id:zecl:20150927160142j:plain
MSRとして、ML(Meta Language)的なアプローチを使った言語設計で研究することが決定したのが2002年らしいので、F#1.0に至るまで約3年かかったということになるのかな。
F#の父 ドンちゃんこと Don Syme 氏は、1998年からマイクロソフトで働き始めて.NET CLRC#(VB) のためのジェネリック機構を作った人。すごい人 #実際すごい

F#の特徴的な機能としては、sequence expression(シーケンス式)、非同期ワークフロー、computation expressions(コンピュテーション式)、Type Provider(型プロバイダー)などの新しい(面白い)試みがある。小さなところでいうと、Active Pattern,(アクティブパターン)なんてのもある。簡単に言うとユーザ指定形式のパターンマッチ。

最新版のF#4.0は、3.0からの大きな機能拡張はなくて割と地味な印象がある。でも、細かなバグの修正だったり手触り感の向上があって普通に便利になりました。あと、デフォではVisual Studioでインストールされなくなりましたが。このあたりは別にどっちでもいいです、

f:id:zecl:20150927160739j:plain
他には、毛色が違うけどリアクティブプログラミングもパラダイムのひとつと言って差支えないかな。

F#は関数プログラミングに主軸を置いたマルチパラダイム言語です。もっと言うと、F# は .NET で 実用レベルで使用できる関数プログラミングパラダイムをサポートしている唯一の言語。それ以上でもそれ以下でもないです。

C#(VB)はオブジェクト指向プログラミングを主体としたマルチパラダイム言語。とはいっても、C#(VB)のそれは関数プログラミングを支援している関数型プログラミング言語に比べて、ごくごく限られていて。C#(VB)でできるプログラミングのパラダイムの1つに関数プログラミングを加えるは、ちょっと違うかなと(個人的に)は思うところです。もちろん、LINQ使用時のラムダ式の利用など関数プログラミングのエッセンスが効果的にとりいれていて、それはオブジェクト指向プログラミングとも非常になじんでいます。

f:id:zecl:20150927161826j:plain
Monoがあることによって、いろんなところで動くよ
他には、GPUとかブラウザ上とか。さまざまな環境で動くF#さん

f:id:zecl:20150927161940j:plain

Fsharpbindingプロジェクトってのがあってですね・・・いろんなエディタいろんな環境でつかえるよ。 https://github.com/fsharp/fsharpbinding

でも、いちばんのオススメは、やはりVisual Studio(現時点ではおそらく最強)。Visual F# Power Tools 拡張機能の充実ぶりがすばらしいので。
一応条件付きとはいえ、Community Editionでフルに使えますし #いい世の中になりました

C#で作られたライブラリも利用可能、とは言ったものの、F#から使いやすいC#ライブラリとして設計されていないと、だいぶツライ感は否めないですけど。はい。

f:id:zecl:20150927162108j:plain
Visual F# Power Toolsの機能をいくつか紹介しました。

f:id:zecl:20150927162153j:plain
C#VBと同等にXMLドキュメントを生成してくれるやつ

f:id:zecl:20150927162408j:plain
クイックサーチ機能ですね

f:id:zecl:20150927162415j:plain
VS標準ではfsproj内のフォルダ作成はサポートされていないので、 フォルダをきって、階層構造をつくれるようになるのはふつうにうれしい。

f:id:zecl:20150927162426j:plain
これまではインターフェイスの実装は、すべて手で記述する必要があった…(圧倒的作業感) 自動生成はありがたい(実際助かる)

f:id:zecl:20150927162635j:plain
レコード型のスタブを生成する機能

f:id:zecl:20150927162706j:plain
判別共用体のパターンマッチケースを網羅的に自動生成してくれるやつ(こちらも助かる)

f:id:zecl:20150927162749j:plain
必要な名前空間やモジュールを追加してくれるやつ C#でいうところの、必要な using ほげもげ を追加してくれるやつ

f:id:zecl:20150927162844j:plain
発音はプラジナでよいのかな



f:id:zecl:20150927163121j:plain
githubですでにα版が公開されたので、興味のある人は見てみたらよいんじゃないでしょうか #か msrccs.github.io www.nuget.org

f:id:zecl:20150927163317j:plain
プログラミングスタイルと、それの支援状況的なアレ

f:id:zecl:20150927163421j:plain
関数型言語関数プログラミングなどは定義が結構あいまいで説明が難しい

f:id:zecl:20150927163612j:plain
おおむね間違っていないと思うが、個人的な見解と雑さがやばい

副作用 is 何 という話もあるが、深入りはやばい #実際やばい ので、ここでは破壊的代入操作や、コンソールや画面描画などの出力を伴う操作ということでお茶を濁す

f:id:zecl:20150927163710j:plain
高階関数の扱いやすさが、 関数型言語っぽさに比例しているかなあと、個人的には考えます。まぁ、関数型言語かどうかを端的にあらわすのであれば、ラムダ計算に基づいているかとかで判断するほうが妥当なのかなあ? 最近のプログラミング言語は、マルチパラダイム化(というか、関数プログラミングの一部の要素が取り入れられる)が進んでいてその境界が割と曖昧になってきている。が、関数プログラミングというスタイルについて 言語(コンパイラ)や開発環境でどの程度支援されているか(推奨されているか)どうかで、関数型言語と呼んで差支えがないかどうか判断をする感じかなあ。

f:id:zecl:20150927163841j:plain
これ。関数型妹botかなんかが流行っていた時期につぶやいたものだったかな? オブジェクト指向プログラミング言語は、オブジェクト指向プログラミングがなんたるかを教えてくれない。 では、関数型言語はどうだろう? かなりのぶぶんで言語そのものから関数プログラミングのスタイルを学ぶことができる。 ある面では学習コストは高いけど、そういった面で考えると、頭の中がまっさらならむしろ学習コスト低いのかななんて。

理解するのに時間がかかるような難しい理論や概念ももちろんありますが、大部分が誤解かと思います。関数型言語を使って関数プログラミングを学ぶ、その入り口自体には難しい要素はほとんどなく、シンプルかつ堅牢なルールが重んじられる(ことが多い)ので複雑性が少なくなって、むしろ簡単とさえ感じる部分もあるくらいです。少なくとも、可変な値に翻弄される複雑性を減らすことができるので、書きたいプログラムそのものに集中できる時間が増える。ということは実際に利用してみると実感できるはずです。

ただし言語によっては大きくシンタックスが異なる場合があるので、ある程度の抵抗感が生まれてしまうのは事実(しょーがない)。F#も「見た目がきもくて無理」なんて言われることもある。好んで使っているひとは「美しい」って言う人多いのに。

F# は(いい意味で)いろいろとゆるいので。みゅーたぶるな値も使い放題だし、手続き的だったりオブジェクト指向なスタイルを残しつつ、少しずつ関数プログラミングのスタイルを取り入れていくことが無理なくできるのではないかな。関数型言語のなかでも、とりわけ難しくない方ではないかなあと思う(個人の感想)

f:id:zecl:20150927164342j:plain
だいぶ釣りだし、実際のところ1分じゃぜんぜん足りない(そりゃそうだ)

某F# for fun and profit という素敵サイトの記事から引用したものです
fsharpforfunandprofit.com
重要なところも割とさっくりと大胆に省略されていたりしますが、まあイサギヨサがある。

そもそも、F# のコードを見たことがない人も多いのでは?ということで入れました。
かなりさらっとやるつもりでいたんですが、ここにかなりの時間を費やしてしまったので時間切れになってしまった。

f:id:zecl:20150927170525j:plain
let キーワードで 不変な値に名前をつけて定義します
明示的に値の型を記述していないこと注意してください(型はコンパイラが推論してくれます)

f:id:zecl:20150927170554j:plain
F# のリストは、順序が指定されていて変更不可の一連の同じ型の要素を表します。

リストを定義するには、セミコロンで要素を区切って角かっこで囲む感じ。
単一要素とリストの結合はコロン2つで。リスト同士の結合は@で。

f:id:zecl:20150927170705j:plain
F# では 返り値を返すときに return キーワードを使用しません。常に関数内の最後の式が返される。
最初こそ少しとっつきにくいかもしれないが、シンプルなルールなのですぐに慣れることができるだろうし、実際明確でわかりやすい。

f:id:zecl:20150927170754j:plain
ふぃぼなっち

f:id:zecl:20150927170839j:plain
リストから偶数のみを取り出す関数
偶数かどうかを判断する isEven が関数内関数として定義されている

リストの対する操作は Listモジュールに定義されているので、よしなに使う。
List.filterはLINQでいうところのWhereのこと。

f:id:zecl:20150927170944j:plain
1から100までのリストについて、正方形の面積を求めてその和をだす(なんのために)

関数に適用される引数を明確にするためには括弧を用います。
この例に関していうと、括弧を書かないとコンパイルが通らないので。

f:id:zecl:20150927171103j:plain
正確には前方パイプライン演算子

F#ではコードを書きやすく、また見通し良くするためのパイプライン演算子が標準で提供されている。

f:id:zecl:20150927171138j:plain
無名関数(ラムダ式)を書くときは fun キーワード使う。 もしかすると楽しい気分を演出するかもしれないし、しないかもしれない

f:id:zecl:20150927171333j:plain
完全に一致(ではない)が、似ている。

F#ではループの代わりとして利用できる高階関数が数多く提供されている。ので、ループしようと思ったら再帰関数書かなきゃだめなの!?みたいな変な誤解は持たないでほしい。C#(VB)のLINQになじみがあれば、LINQ to Objectsを使えば for や foreach などのループ用の構文を必要としない場面が多いということはわかってもらえるはず。

f:id:zecl:20150927171612j:plain
LINQの場合は当然、あらかじめ定義されている拡張メソッドなりがある場合のみにメソッドチェーンとして処理を手続き的に書き下すことができる。それに対してパイプライン演算子によるチェーンでは、型さえ合えば自由に関数をチェーンできる。果てしなく。
ただ、後ろになんでも繋げられることをメリットととらえるか、はたまたデメリットととらえるか。どちらも正しい。これは、開発のスタイルや重視するプログラミングパラダイムによって意見が変わってくるところだろうと思う。関数プログラミングを主体とするF# においては、パイプライン演算子によって後続の処理を好きなだけ連ねることができるのはメリットでしかない。

f:id:zecl:20150927171906j:plain
3年前のツイートだった

わたしはこれでF#覚えました。これは別に冗談で言っているのではなく結構本気で。(|>)パイプライン演算子という中置演算子を用いることで、関数と引数の順序を逆にすることができる。これによって、関数適用の流れを手続き型的に書き下すことができるので、処理の流れがわかりやすくなります。F#ではこの「パイプライン演算子を使う」ことが基本でありながら、同時に最上級のプラクティスであると言っても過言ではなく。これを好んでよく使うことはおのずとF#の上達に繋がります。

f:id:zecl:20150927172312j:plain
複数の値を組みにするやつ。
雑に言うと、フィールド名を持たない無名クラスのようなもの

f:id:zecl:20150927172348j:plain
System.Tuple.Create<,>とか書かなくてよいし、Item1,Item2…と付き合わなくてもよいという話。
多くの C# 開発者は タプル扱いやすく改善されないかなぁと思っているはず。 ちなみにF#のそれ。この場合かっこ(パーレン)も省略できる
あ、匿名型は F# にはないです。 F# でもたまーに欲しいシーンはあるので、ちょっと欲しいです。

f:id:zecl:20150927172657j:plain
match式は雑にいうと、 switch 文の強力版

ただし、match式はパターンマッチのほんの1例にすぎない。この例だと、あまりありがたみはないが、F#にはさまざまな形式のパターンマッチが提供されているので、非常に便利。

f:id:zecl:20150927172823j:plain
雑に言うと、タプルの各要素(フィールド)に名前つけたやつ 名無しの権兵衛さん

f:id:zecl:20150927172852j:plain
レコード型をパターンマッチで分解しているの図。 突然の and !だったりするが華麗にスルーで。

f:id:zecl:20150927172959j:plain
リストもパターンマッチで分解できる例

他にも、ユーザ指定形式のパターンマッチであるところの、Active Pattern,(アクティブパターン)なんてのもある。

f:id:zecl:20150927173044j:plain
なんか見たことあるやつ。動物抽象クラスを継承して動物たちが鳴くやつ。

f:id:zecl:20150927173206j:plain
突然の function式 ! だが、ここもスルーで(機能的にはmatch式と同じでその引数省略できる版)

いわゆる代数的なデータ型的なやつ。一部誤解を与えてしまう可能性もあるが、ある種のクラス階層を表現するのに使える。
オブジェクト指向プログラミングの「継承」と明らかに違う点は、まったく性質の異なるものを同質のものとみなして定義することが出来る点、かなあと思う。

f:id:zecl:20150927173514j:plain

これを難しいと言われると、もうどうしようもない。

f:id:zecl:20150927173835j:plain
カーリーブレイス。まあつまり中括弧のことなわけですが。洞窟物語のキャラにカーリーブレイスって居たなと。

スコープがインデントで区切られるという構造のオフサイドルール(軽量構文)。Pythonインスパイア。
これに対して、インデントにしばられない冗語構文もあるが、(どうとでもなるので)そっちは別段覚えなくてもよいと思う(個人の感想)

オフサイドルールは最初こそ少しとっつきにくいかもしれないが、ルールがシンプルなのですぐに慣れることができるだろうし、実際明確でわかりやすいように思う。ただ、人によっては「見た目キモすぎぃぃぃ」と言う反応をする方もいる。それも理解できないこともない。慣れないものを見ると拒絶反応を示すというのはごくごく当たり前の反応だし。無理なものは無理だし。生理的に受け付けないので付き合えません!(No Thank you!)とかもまあ現実世界でも実際あるわけだし、世知辛いですね(なんの話)

f:id:zecl:20150927174252j:plain
唐突には挿入した息抜き用の画像。 ぐらばく(@Grabacr07) さんが作ってくれたものです。頼んでもいないのに。(写真の人物本人の使用許可あり) かなりの謎コラだけど、非常によい表情です。

f:id:zecl:20150927212744j:plain

f:id:zecl:20150927174834j:plain
変数は、値にわかりやすい名前を付けて定義しておくことで、続くコードで再利用するためのもの。
let で変数を作り出すことを変数束縛と言います(くどい)

f:id:zecl:20150927175027j:plain
例えば破壊的代入(再代入)を許すようなプログラムでは、変数が異なる状態を持ち得るのでその変数を参照する場合「この変数の今の値は何だろう?」と観測しなければならなくなり、複雑性を生み出す要因となる。つまり心配ごとが増える。

f:id:zecl:20150927175436j:plain
let による変数束縛ではデフォルトで破壊的代入(再代入)ができません。が、mutable宣言をすることで、破壊的代入が可能な変数として宣言することもできます。しかし、関数プログラミングというスタイルでは極力「破壊的な状態の変化」というものを避ける傾向にあるので、破壊的代入をデフォルトで許さないようにしている。これはスタイルとしての「副作用をできるだけ使わない」ということを推奨/支援しているとも言える。

f:id:zecl:20150927175507j:plain
例えば変数が状態を持ってしまうと、その変数を参照する箇所で「この変数の今の値は何だろう?」と注意しなければならない。

f:id:zecl:20150928092712j:plain
この例においては、2番目の出力は「5963」ではなく「4649」と表示される。

F#は、変数を後から宣言した同名の変数でシャドウイング(隠ぺい)することができる。シャドウィングが使えることで、破壊的代入をしなくても不便さはそれほどなくなる。また、プログラムのスコープが明確になり、書きやすいだけではなく非常に読みやすいプログラムとなる。

f:id:zecl:20150928092752j:plain
immutableな値として、同名の変数として宣言するシャドウィングを用いる場合、 スコープの中の直前のものにのみ着目すればよいので、余計な複雑さを排除できてコードの見通しがくなり、プログラミングそのものに集中できる。 ※同一モジュール上のlet 宣言をシャドウィングすることはできないという制限あり

f:id:zecl:20150927180036j:plain
プログラマーのかわりに関数を利用しているコードの型などから、コンパイラがよしなに型をつけてくれる型推論。関数の引数や戻り値にも型を書かなくてよいし、可能であればジェネリックな関数として自動的に推論してくれたりする。 変数の定義も関数の定義も、letというキーワードで統一的に定義できるようになっていてうれしい。

少し乱暴だが、F#では let キーワードを覚えるだけで、かなりのプログラミングが書ける。match式あるいは if 式を覚えれば条件分岐もできる。 くわえて 再帰のための let rec を覚えれば、ループ処理が書けるので、いとも簡単に三種の神器を手に入れることができる(アッハイ)

f:id:zecl:20150927181717j:plain

f:id:zecl:20150927181745j:plain
JavaScriptのコードでカリー化関数と部分適用の説明。 突然のJavaScript!なのだが、社内勉強会用に作った資料の流用だったりするので。

f:id:zecl:20150927181853j:plain
f:id:zecl:20150927182004j:plain
F# ではカジュアルに無意識にカリー化関数が書けるので、うれしいという話

f:id:zecl:20150927182101j:plain
高階関数のうれしいところ

f:id:zecl:20150927182147j:plain
高階関数を扱いやすくするのに必要な機能とかの話。 F#では関数内関数が簡単にかけてうれしい。

f:id:zecl:20150927182253j:plain
高階関数を書きやすくする要因のひとつとして、関数内関数が無理なくかけるかというのがある。

C# でも書けないこともないが、どうしても書きにくいので書くモチベーションにならない。 すすんで書くようなものではないことは多くの人が知っているし、C# では素直に名前を付けてメソッドとして切り出して書くべきだ。

F#では、無理なく関数内関数を書くことができるのでなんの抵抗も生まれないし、その場限りの関数であれば、関数内関数として定義することはごくごく当たり前に行われる。これは、インデントによるオフサイドルールとも相性が良く、書き方/スタイルとして非常になじむ。関数プログラミングを支援/推奨している言語では プログラミングスタイルそのものが変わります。

f:id:zecl:20150927183756j:plain
関数の合成のしやすさも、関数プログラミングのしやすさの指標と考えられます。C#で合成関数を書こうとするとかなり骨が折れます。しかもこれは、特定の型に関する合成しかできません。

F#で定義した関数は、コンパイラ型推論と自動ジェネリック化のメカニズムによって、可能であれば暗黙的にジェネリックな関数となります。これにより非常にシンプルな記述で、あらゆる型の関数を合成するような関数(演算子)が表現できてしまうというわけです。こういった特徴を兼ね備えているので、小さな関数を巧みに組み合わせて、より大きな関数を構築していくという関数プログラミングというプログラミングスタイルが違和感なく行えます。

f:id:zecl:20150927184323j:plain
レキシカルスコープのほうが、コードを追いやすい話。 ダイナミックスコープと言えば、Lisp とか?

f:id:zecl:20150927184502j:plain
仮にダイナミックなスコープだとすると、10 が出力される ダイナミックスコープで解決されてうれしい場面ってどの程度あるのだろうか。罠でしかない感。

F#はレキシカルスコープを採用しているので、オフサイドルールやシャドウィングの仕様ともよくマッチしていて人道的でわかりやすいスコープとなっている。なので F# のコードは非常に読みやすい(追いやすい)。これが仮にダイナミックなスコープだとすると、関数を適用したときに、どのような結果をもたらすかコードリーディングだけで判別しにくくなってしまう。高階関数とかこわくて使えない。

f:id:zecl:20150927185203j:plain
高階関数の利用を容易にする条件はこんな感じかな 言い換えると、関数プログラミングしやすい条件ともいえる。


ここから、「続きはWebで」のぶぶん
f:id:zecl:20150927185552j:plain
有名なアレ。 VBの方ですか?Nothingもっとこわい?

f:id:zecl:20150927185713j:plain
C#でも null非許容型が欲しいなんて話はたびたび聞きます。 テストでカバーすればなんとかなる? そういう話ではないんです。

f:id:zecl:20150927185818j:plain
F# では通常、null 値を値にも変数にも使用しません。デフォルトで危険性を回避するように設計されています。例外的な場合を除いて、nullの使用はできる限り避けるよう言語設計されています。

f:id:zecl:20150927190029j:plain
通常F#で定義されているクラスには null は代入できません。 ムリヤリつっこうもとしてもコンパイルエラーとなります。

f:id:zecl:20150927190144j:plain
そうは言っても、.NET Frameworkの上にある以上 F# でも null 値を扱うことはあります。 ただし、その状況はとても限られていて

  • .NET API を呼び出して引数として null を渡す場合
  • .NET のメソッド呼び出しからの戻り値または出力パラメーターを解釈する場合

のいずれかしかありません。これらの状況に対しては AllowNullLiteral 属性を使用して対応します。
これを使用することで null 許容する型を明示的に定義することができます。

この例ではその2つの状況いずれにも当てはまらないので、 AllowNullLiteral は使用すべきではありません。
また、null チェックは強制することができないので、チェック漏れがあれば当然 NullReferenceExceptionとなります。

ちなみに、F#で定義されていてF#からのみ使用する型の場合、null 値を作成する方法は、 Unchecked.defaultof または Array.zeroCreate のいずれかの関数を使用した場合に限られます。



f:id:zecl:20150927190535j:plain
とはいえ、値がない状態というのをプログラミングで表現したいシーンはたくさんあります。そんなときに役立つのがオプション型で、これにより「値がないかもしれない」ということを型として明示することができます。計算不能や計算失敗などにより、実際の値が存在しない場合などに使えます。null の厄介な点は null であることが型の情報として現れないことで。nullは参照型であればどんな型の値にもなり得るので、 null参照によるエラーというのは実行してみるまで誰にも分からないからです。つまり、nullが来るかどうかの判定をプログラマーが正確に管理しなければならないこと意味します。これは実際難しいことです。

f:id:zecl:20150927190812j:plain
オプション型を導入することで、 null値を使用することなく安全に「値がない状態」を表すことができます。

f:id:zecl:20150927190935j:plain
関数プログラミングとは直接は関係ないところですが、F# のとても面白い(エキサイティングな)機能なのでご紹介します。

f:id:zecl:20150927191038j:plain
「インフォメーションリッチプログラミングから LINQ を引いて残った物が 型プロバイダーだよ。」「わけがわからないよ。」

TypeProviderのドキュメントによると、「基本的に定型のデータあるいはサービス情報空間をF#プログラミング内に導入することを目的としています 」とのこと。コンパイル時に型のない情報に型を与えることで、F# コード上であらゆる情報を安全に扱えるようにする仕組み。

f:id:zecl:20150927191108j:plain
型プロバイダーの主目的はコンパイル時プログラミングではないものの、型のないものを扱う際に生じやすいしょーもないバグを未然に防ぐことができるソリューションと解釈することもできます。型のないものを安全に扱える世界があなたの手中にといったところです。

f:id:zecl:20150927192212j:plain
ごむごむ

f:id:zecl:20150927214004j:plain
いろいろできそうです(オラワクワクしてきたぞ)

でも、TypeProviderはDSLなどをメタプログラミングするためのものではないと、TypeProviderのドキュメントに書かれています。
ですがが、まぁ無視してしまって全然よい気はしますね(実際にさまざまなTypeProviderでかなり無視されている) 特に学習目的であればメタプログラミング目的の方がとっつきやすいかもしれませんので。



f:id:zecl:20150927192302j:plain
NuGetからTypeProviders.StarterPack を導入するのがもっとも近道。 TypeProviderを作る際に必要な便利部品がひととおり用意されている。

f:id:zecl:20150927192351j:plain
スキーマが動的に変化することは想定されていないので、スキーマがコーディング中やプログラムの実行中に安定しているかということは、もちろん前提として必要。

ここで言う .NET の型システムへのマッピングとは、つまりクラス だったり 構造体だったりに対するマッピング。F# の型システムと言っているのは、主に判別共用体やレコード型に対するマッピングを意味している。関数プログラミングとの親和性を考えて、F# の型システムの型を生成するのか、あるいはオブジェクト指向プログラミングになじみやすいような型を生成するのか、そのあたりはよく検討してデザインする必要がある。

関数プログラミングとの親和性をとる場合の例でいうと、判別共用体は再帰的な構造を表現するのにとても適正しているので、冒頭で紹介した弾幕記述言語の F# 実装であるところの FsBulletMlでは実際に、XML(外部DSL)から判別共用体(型付き内部DSL)への安全なマッピングのためのTypeProvider提供しています。

f:id:zecl:20150927193158j:plain
セッションでは、いちおう簡単なDemoだけ紹介しました。



f:id:zecl:20150927194029p:plain

f:id:zecl:20150927194037p:plain
コンパイル時にメタデータからリアルタイムで型がつくられる。Visual Studioとも連携しているので、インテリセンスも効くという感じ。
こんな簡単なDemoからでも、「TypeProviderでなんか面白いことができそうだな!」ということが容易に想像できると思う。


f:id:zecl:20150927194247j:plain
今回のDemoのような単純なものであれば少し勉強すれば、すぐに作れるようになりますが、ある程度複雑なものになると、ぐんと難しくなります。
ただ、それは関数プログラミング的な側面で難しいという意味ではなく、メタプログラミングの側面として難しいという意味です。

TypeProviderの作り方について学ぶには、日本語情報に限らず海外の情報もまだまだ少ないので、 FSharp.Data等のライブラリのソースを読んで勉強する感じになるかと思います。 github.com

f:id:zecl:20150927194634j:plain

f:id:zecl:20150927194644j:plain
F#に限らずさまざまな言語の話も飛び交う感じの割とフリーダムなゆるい集まり。
私も何度かお邪魔して楽しくすごさせていただいています。ほとんどF#を書いたことがないというような人でも気軽に参加していただける勉強会です。
F#に詳しい参加者も多いので、やさしいF#erにマンツーマンでわからないことをいろいろ教えてもらえる(かも!?)

f:id:zecl:20150927220102j:plain
日本全国のF#er の集まり(online)という位置づけ(のはず)

gitterで F# に関する情報交換などがなされています gitter.im



f:id:zecl:20150927194719j:plain
英語ですが、F#に関するさまざまな情報がまとまっています(無料会員登録可) 特に言語の発展に物申したい場合は有料会員になる感じだと思います。 F# Software Foundation

@yukitos さんは、こちらのボードメンバーでもあります。

f:id:zecl:20150927195313j:plain
f:id:zecl:20150927195323j:plain
他のプログラミング言語に比べてF#が特別難しいというようなことはありません(もちろん難しい部分も当然あります)。

F#は高階関数が扱いやすく関数プログラミングがしやすい言語です。なので、プログラミングのスタイルは自然と関数プログラミングに軸をおいたものとなります。


よく、F#って何に使えるんですか?等の質問をいただきますが、VBC#とほとんど同じ場面で使えると同じように、ほとんどの場面で同じようにF#も使えます。F#を選択する理由があるとするならば、関数プログラミングのスタイルおよびそれによって享受できるメリットを重視するかしないかくらいのものです。それ以上でもそれ以下でもありません。関数プログラミングのスタイルを重視しないのであれば、選ぶ理由はないでしょう。 現状、世間一般ではそれを重視しないのが多数派であり、人材の確保が難しかったりある程度学習コストが高いという側面があるので、選択肢としてあがることも少なく(んなもんで人材が増えないという悪循環)、結果「流行っていない」ということになります。

手続き寄りの一般的なプログラミングを習得している人に対して、抽象化の道具として新たに関数プログラミングを軸にすることを提案することは 実際間違いではないし、どちらかというと筋がよいことだと思うんだけど、それを必要としている人もいるししてない人もいるというのは理解できます。で、実際いまのところは(残念ながら)必要とされていない(らしい)ので、F#流行っていないということになります。大変良い言語(実際)ですが、今のところMSが推す気配なし!ということもあって、だいぶ闇は深いです。

f:id:zecl:20150927200510j:plain

長々と(ポエム)書きました(しゃべりました)が、少しでも興味を持ってもらえたなら、うれしいな #うれしいな