この投稿は、仕事でF#を低リスクかつ段階的に使う方法に関するシリーズの結論です。
最後に、コアや重要なコードに影響を与えることなく、F#がさまざまな開発タスクの周辺でどのように役立つかについて、いくつかの方法を見ていきます。
シリーズの内容
本題に入る前に、26の方法の完全なリストを示します:
パート1 - F#を使って対話的に探索し開発する
1. F#を使って.NETフレームワークを対話的に探索する
2. F#を使って自分のコードを対話的にテストする
3. F#を使ってWebサービスを対話的に操作する
4. F#を使ってUIを対話的に操作する
パート2 - 開発およびDevOpsスクリプトにF#を使う
5. ビルドとCIスクリプトにFAKEを使う
6. Webサイトの応答をチェックするF#スクリプト
7. RSSフィードをCSVに変換するF#スクリプト
8. WMIを使ってプロセスの統計をチェックするF#スクリプト
9. クラウドの設定と管理にF#を使う
パート3 - テストにF#を使う
10. 読みやすい名前の単体テストをF#で書く
11. F#を使って単体テストをプログラムで実行する
12. F#を使って他の方法で単体テストを書くことを学ぶ
13. FsCheckを使ってより良い単体テストを書く
14. FsCheckを使ってランダムなダミーデータを作成する
15. F#を使ってモックを作成する
16. F#を使って自動化されたブラウザテストを行う
17. 振る舞い駆動開発にF#を使う
パート4. データベース関連のタスクにF#を使う
18. F#を使ってLINQpadを置き換える
19. F#を使ってストアドプロシージャの単体テストを行う
20. FsCheckを使ってランダムなデータベースレコードを生成する
21. F#を使って簡単なETLを行う
22. F#を使ってSQL Agentスクリプトを生成する
パート5: F#を使うその他の興味深い方法
23. パーシングにF#を使う
24. ダイアグラムと可視化にF#を使う
25. WebベースのデータストアへのアクセスにF#を使う
26. データサイエンスと機械学習にF#を使う
(ボーナス)27: イギリスの発電所群の発電スケジュールをバランスさせる
パート5: コアの外でF#を使うその他の方法
この最後のグループの提案は、申し訳ありませんが、少し雑多なものです。 これらは主に分析とデータ処理にF#を使うことに関するもので、前回の投稿には収まらなかったものです。
23. パーシングにF#を使う
日常的な開発の過程で、何かをパースする必要がある場面は驚くほど多いです:文字列をスペースで分割する、CSVファイルを読み込む、 テンプレートで置換を行う、Webクローラー用にHTMLリンクを見つける、URIのクエリ文字列をパースするなど。
F#はML由来の言語であり、簡単な正規表現から本格的なパーサーまで、あらゆる種類のパーシングタスクに理想的です。
もちろん、一般的なタスクには多くの既製ライブラリがありますが、時には独自のものを書く必要があります。 良い例は、先ほど見たBDDフレームワークのTickSpecです。
TickSpecは、Given/When/Thenのいわゆる「Gherkin」形式をパースする必要があります。別のライブラリに依存するよりも、 Philにとっては、数百行で独自のパーサーを書く方が簡単(そして楽しい)だったのではないかと想像します。 ソースコードの一部はこちらで見ることができます。
独自のパーサーを書く価値があるもう一つの状況は、ひどいXML設定形式を持つ複雑なシステム(ルールエンジンなど)がある場合です。 設定を手動で編集する代わりに、非常に単純なドメイン固有言語(DSL)を作成し、それをパースして複雑なXMLに変換することができます。
Martin FowlerはDSLに関する彼の本で、 この例を挙げています。ステートマシンを作成するためにパースされるDSLです。 そして、こちらがそのDSLのF#実装です。
より複雑なパーシングタスクには、FParsecの使用を強くお勧めします。これはこの種のことに完璧に適しています。 たとえば、以下のパーシングに使われています: FogCreekの検索クエリ、 CSVファイル、 チェス表記、 負荷テストシナリオ用のカスタムDSL。
24. ダイアグラムと可視化にF#を使う
何かをパースまたは分析した後、データでいっぱいの表よりも、結果を視覚的に表示できると常に良いです。
たとえば、以前の投稿で、GraphVizと組み合わせてF#を使い、 依存関係のダイアグラムを作成しました。以下にサンプルを示します:
ダイアグラム自体を生成するコードは短く、約60行だけでした。 こちらで見ることができます。
GraphVizの代替として、FSGraphの使用も検討できます。
より数学的またはデータ中心の可視化には、いくつかの優れたライブラリがあります:
- FSharp.Charting - F#スクリプティングとよく統合されたデスクトップ向け可視化。
- FsPlot - HTMLでのインタラクティブな可視化。
- VegaHub - Vegaと連携するF#ライブラリ。
- F# for Visualization
そして最後に、800ポンドのゴリラ - Excelがあります。
利用可能であれば、Excelの組み込み機能を使うのは素晴らしいです。そしてF#スクリプティングはExcelとうまく連携します。
Excelでチャートを作成したり、 Excelで関数をプロットしたりできます。さらにパワフルな統合のために、 FCellやExcel-DNAプロジェクトがあります。
25. WebベースのデータストアへのアクセスにF#を使う
Web上には、引き出して愛されるのを待っている多くの公開データがあります。 型プロバイダーの魔法により、F#はこれらのWeb規模のデータストアをワークフローに直接統合するのに適しています。
ここでは、FreebaseとWorld Bankという2つのデータストアを見ていきます。 近々さらに多くのものが利用可能になる予定です - 最新情報はfsharp.orgのデータアクセスページを参照してください。
Freebase
このセクションのコードはgithubで入手可能です。
Freebase)は、多くのソースから収集された構造化データの大規模な協力型知識ベースとオンラインコレクションです。
始めるには、これまで見てきたように型プロバイダーのDLLをリンクするだけです。
このサイトはスロットル制限があるため、頻繁に使う場合はAPIキーが必要になるでしょう (APIの詳細はこちら)
// 現在のディレクトリをスクリプトディレクトリと同じに設定
System.IO.Directory.SetCurrentDirectory (__SOURCE_DIRECTORY__)
// スクリプトディレクトリ下にFSharp.Dataが必要
// nuget install FSharp.Data -o Packages -ExcludeVersion
#r @"Packages\FSharp.Data\lib\net40\FSharp.Data.dll"
open FSharp.Data
// キーなし
let data = FreebaseData.GetDataContext()
// キーあり
(*
[<Literal>]
let FreebaseApiKey = "<ここにfreebase対応のgoogle APIキーを入力>"
type FreebaseDataWithKey = FreebaseDataProvider<Key=FreebaseApiKey>
let data = FreebaseDataWithKey.GetDataContext()
*)
型プロバイダーがロードされたら、次のような質問を始めることができます...
「アメリカの大統領は誰?」
data.Society.Government.``US Presidents``
|> Seq.map (fun p -> p.``President number`` |> Seq.head, p.Name)
|> Seq.sortBy fst
|> Seq.iter (fun (n,name) -> printfn "%sは%i番目でした" name n )
結果:
George Washingtonは1番目でした
John Adamsは2番目でした
Thomas Jeffersonは3番目でした
James Madisonは4番目でした
James Monroeは5番目でした
John Quincy Adamsは6番目でした
...
Ronald Reaganは40番目でした
George H. W. Bushは41番目でした
Bill Clintonは42番目でした
George W. Bushは43番目でした
Barack Obamaは44番目でした
たった4行のコードでこれだけできるのは悪くありません!
では、「カサブランカはどんな賞を受賞した?」はどうでしょうか?
data.``Arts and Entertainment``.Film.Films.IndividualsAZ.C.Casablanca.``Awards Won``
|> Seq.map (fun award -> award.Year, award.``Award category``.Name)
|> Seq.sortBy fst
|> Seq.iter (fun (year,name) -> printfn "%s -- %s" year name)
結果は:
1943 -- Academy Award for Best Director
1943 -- Academy Award for Best Picture
1943 -- Academy Award for Best Screenplay
以上がFreebaseです。役立つものもあれば些細なものもある、たくさんの良い情報があります。
Freebaseを使って現実的なテストデータを生成する
FsCheckを使ってテストデータを生成する方法を見てきました。 同様に、Freebaseからデータを取得することで、より現実的なデータを得ることができます。
Kit Easonがツイートでこの方法を示しました。 以下は彼のコードに基づく例です:
let randomElement =
let random = new System.Random()
fun (arr:string array) -> arr.[random.Next(arr.Length)]
let surnames =
FreebaseData.GetDataContext().Society.People.``Family names``
|> Seq.truncate 1000
|> Seq.map (fun name -> name.Name)
|> Array.ofSeq
let firstnames =
FreebaseData.GetDataContext().Society.Celebrities.Celebrities
|> Seq.truncate 1000
|> Seq.map (fun celeb -> celeb.Name.Split([|' '|]).[0])
|> Array.ofSeq
// 10人のランダムな人物を生成して表示
type Person = {Forename:string; Surname:string}
Seq.init 10 ( fun _ ->
{Forename = (randomElement firstnames);
Surname = (randomElement surnames) }
)
|> Seq.iter (printfn "%A")
結果は:
{Forename = "Kelly"; Surname = "Deasy";} {Forename = "Bam"; Surname = "Br?z?";} {Forename = "Claire"; Surname = "Sludden";} {Forename = "Kenneth"; Surname = "Kl?tz";} {Forename = "?tienne"; Surname = "Defendi";} {Forename = "Billy"; Surname = "Paleti";} {Forename = "Alix"; Surname = "Nuin";} {Forename = "Katherine"; Surname = "Desporte";} {Forename = "Jasmine"; Surname = "Belousov";} {Forename = "Josh"; Surname = "Kramarsic";}
世界銀行
このセクションのコードはgithubで入手可能です。
Freebaseとは対照的に、世界銀行オープンデータは、世界中の詳細な経済・社会情報を多く持っています。
セットアップはFreebaseと同じですが、APIキーは必要ありません。
// 現在のディレクトリをスクリプトディレクトリと同じに設定
System.IO.Directory.SetCurrentDirectory (__SOURCE_DIRECTORY__)
// スクリプトディレクトリ下にFSharp.Dataが必要
// nuget install FSharp.Data -o Packages -ExcludeVersion
#r @"Packages\FSharp.Data\lib\net40\FSharp.Data.dll"
open FSharp.Data
let data = WorldBankData.GetDataContext()
型プロバイダーをセットアップしたら、次のような本格的なクエリを実行できます:
「低所得国と高所得国の栄養失調率を比較するとどうなりますか?」
// 処理する国のリストを作成
let groups =
[| data.Countries.``Low income``
data.Countries.``High income``
|]
// 特定の年の指標からデータを取得
let getYearValue (year:int) (ind:Runtime.WorldBank.Indicator) =
ind.Name,year,ind.Item year
// データを取得
[ for c in groups ->
c.Name,
c.Indicators.``Malnutrition prevalence, weight for age (% of children under 5)`` |> getYearValue 2010
]
// データを表示
|> Seq.iter (
fun (group,(indName, indYear, indValue)) ->
printfn "%s -- %s %i %0.2f%% " group indName indYear indValue)
結果は:
Low income -- Malnutrition prevalence, weight for age (% of children under 5) 2010 23.19%
High income -- Malnutrition prevalence, weight for age (% of children under 5) 2010 1.36%
同様に、以下は妊産婦死亡率を比較するコードです:
// 処理する国のリストを作成
let countries =
[| data.Countries.``European Union``
data.Countries.``United Kingdom``
data.Countries.``United States`` |]
// データを取得
[ for c in countries ->
c.Name,
c.Indicators.``Maternal mortality ratio (modeled estimate, per 100,000 live births)`` |> getYearValue 2010
]
// データを表示
|> Seq.iter (
fun (group,(indName, indYear, indValue)) ->
printfn "%s -- %s %i %0.1f" group indName indYear indValue)
結果は:
European Union -- Maternal mortality ratio (modeled estimate, per 100,000 live births) 2010 9.0
United Kingdom -- Maternal mortality ratio (modeled estimate, per 100,000 live births) 2010 12.0
United States -- Maternal mortality ratio (modeled estimate, per 100,000 live births) 2010 21.0
26. データサイエンスと機械学習にF#を使う
これらの提案をすべて実践しているとします。FParsecでWebログを解析し、 SQL型プロバイダーで内部データベースから統計を抽出し、 Webサービスから外部データを取得しています。これらのデータを全て手に入れました - それで何ができるでしょうか?
最後に、データサイエンスと機械学習にF#を使うことについて簡単に見てみましょう。
これまで見てきたように、F#は探索的プログラミングに適しています - インテリセンス付きのREPLがあります。しかし、PythonやRとは異なり、 コードは型チェックされるので、2時間の処理ジョブの途中で例外によってコードが失敗することはありません!
PythonのPandasライブラリやRの'tseries'パッケージに馴染みがあれば、 Deedleを真剣に検討すべきです。これは使いやすく、高品質なデータおよび時系列操作用のパッケージです。 DeedleはREPLを使った探索的プログラミングに適していますが、効率的にコンパイルされた.NETコードでも使えます。
そして、Rをよく使う場合は、R型プロバイダー(もちろん)があります。 これは、RパッケージをあたかもNETライブラリであるかのように使えることを意味します。素晴らしいですね!
他にもF#フレンドリーなパッケージがたくさんあります。fsharp.orgでそれらについて知ることができます。
シリーズのまとめ
ふう!長い例のリストと多くのコードを見てきました。最後まで読んでいただいた方、おめでとうございます!
これによってF#の価値について新しい洞察が得られたことを願っています。 F#は単なる数学的または金融的な言語ではありません - 実用的な言語でもあります。 そして、開発、テスト、データ管理のワークフローにおけるあらゆる種類のことに役立ちます。
最後に、このシリーズを通じて強調してきたように、これらの使い方はすべて安全で、リスクが低く、段階的です。最悪の場合でも何が起こるでしょうか?
さあ、チームメイトや上司を説得してF#を試してみてください。そしてその結果を教えてください。
追記
この投稿の後、Simon Cousinsがツイートで1つ忘れているものがあると指摘しました - 追加せずにはいられません。
@ScottWlaschin 27: イギリスの発電所群の発電スケジュールをバランスさせる。本気で、#fsharpの代替案はリスクが高すぎた
— Simon Cousins (@simontcousins) 2014年4月25日
Simonの実世界でのF#の使用(発電用)について、彼のブログでもっと読むことができます。 fsharp.orgにはF#についてのさらなる証言があります。