F#の基礎(?)
bleis-tift
2016年06月11日
自己紹介
・id:bleis-tift / @bleis
・株式会社オンザロード
・F#が好き
・Excelは便利
今日話すこと
・F#の基礎について?
・(型なし)ラムダ計算の話はもうやったし・・・
・型付きラムダ計算?
・今日思いついたので、その話は次の機会で
今日話すこと
・F#のことをまんべんなく?
・ゆるくいきましょう
F#について
F#ってこんな言語1
・.NET系言語 (C# / VB)
・OCamlを参考にした構文
・静的型 / 型推論
・メインパラダイムは関数型
・VB
・etc
F#ってこんな言語1 - .NET系言語
・コンパイルするとIL(中間言語)になる
・ILは.NET Runtime上で動く
・ILを吐く言語との相互運用可能
・C#
・末尾呼び出しのための命令(prefix)を持っていたりする
・コンストラクタ呼び出しとメソッド呼び出しは別命令
・(F#では統一的に扱える)
・メソッド呼び出しは2種類(call/callvirt)ある
・関数ポインタ経由での呼び出し含めると3種類(calli)
F#ってこんな言語1 -- IL
・スタックマシン
・評価スタック / 呼び出しスタック
・オブジェクトヒープ
・ローカル変数ストア
・CompiledName属性で命名規約を合わせる
F#ってこんな言語1 -- .NET言語との親和性
・F#からの呼び出しは簡単
・F#の呼び出しは注意が必要
・カリー化形式の関数はILでは多引数メソッドで表現
・判別共用体はインターフェイスを実装し公開
F#ってこんな言語1 - 構文
・ML系の文法
・軽量構文
・インデント
・ML系の文法を簡略化
F#ってこんな言語1 -- 冗語構文
// 行コメントが使える
let someFunction arg =
let x = f arg in // let式はinが必要
let y = g arg in
[ x; // リストの要素の区切りには;が必要
y ]
F#ってこんな言語1 -- 軽量構文
// 行コメントが使える(ので、//演算子は定義できない・・・)
let someFunction arg =
let x = f arg // 軽量構文ではinが不要
let y = g arg
[ x // 軽量構文では;を改行+インデントで代替可能
y ]
F#ってこんな言語1 -- matchのネスト
// OCamlerにはうれしい(?)match式のネスト
match f x with
| None -> None
| Some x ->
match g x with
| None -> None
| Some x -> h x
・オブジェクト指向プログラミング
・クラスベース
F#ってこんな言語1 - パラダイム
・関数プログラミング
・正格
・非純粋
・手続き型プログラミング
F#ってこんな言語2
・アクティブパターン
・コードクォート
・コンピュテーション式
・Type Provider
・ScalaのExtractorやHaskellのview patterns
F#ってこんな言語2 - アクティブパターン
・実際の構造と判別方法を切り離して定義
・実装をアクティブパターンの後ろに隠す
・複数の判別方法の提供
・構造のない型に構造を後付け
F#ってこんな言語2 -- アクティブパターン
// アクティブパターンの定義
let (|Even|Odd|) n =
if n % 2 = 0 then Even else Odd
// 定義したアクティブパターンに基づいた分岐
let f = function
| Even -> printfn "even"
| Odd -> printfn "odd"
・小さいコードが巨大な式木を生み出すことがある
・仕様です
F#ってこんな言語2 - コードクォート
・コードをデータとして扱う仕組み
・いわゆる式木
・式木にしてしまうと、標準では実行する手段がない
・外部ライブラリを使えば可能
F#ってこんな言語2 -- コードクォート
let expr =
<@ let x = 42
Console.WriteLine(x.ToString()) @>
// Let (x,
// Value (42),
// Call (None,
// WriteLine,
// [Call (Some (x), ToString, [])]))
F#ってこんな言語2 - コンピュテーション式
・言語の用意する構文をカスタマイズする仕組み
・モナド用の構文としてのコンピュテーション式
・言語内DSLの土台としてのコンピュテーション式
・正しく全部実装するのは難易度高い
F#ってこんな言語2 -- Maybeモナド
// ビルダーを定義して、
type MaybeBuilder () =
member __.Return(x) = Some x
member __.Bind(x, f) = Option.bind f x
let maybe = MaybeBuilder()
// 使う
let someFunc arg =
maybe {
let! x = f arg
let! y = g x
let! z = h y
return z
}
F#ってこんな言語2 -- 言語内DSLの例
// F#向けテスティングフレームワーク
let ``f should throw HogeException`` = test {
let! e = trap { it (f ()) }
do! e.GetType() === typeof<HogeException>
}
let ``g should return correct list`` =
let test (arg, expected) = test {
do! g arg === expected
}
parameterize {
source [
(0, [])
(1, [0])
(2, [0; 1])
]
do! test
}
F#ってこんな言語2 -- Type Provider
・コンパイル時にメタデータから型を生成
・コードの自動生成ではない
・消去型と生成型
F#ってこんな言語2 -- 消去型TP
・型はコンパイル時のみ
・実行時は消去され、ベースの型の操作に置き換わる
・生成型よりも手軽
F#ってこんな言語2 --- 消去型TPの例
type RecordRegex = Regex< @"(?<Name>^[^,]+),s*(?<Address>.+)" >
let res = RecordRegex().Match("山田太郎, どこか")
let name = res.Name.Value
let address = res.Address.Value
(* コンパイルすると、下記のコードと同じコードに展開される *)
// RecordRegexという型は消える
let res =
Regex(@"(?<Name>^[^,]+),s*(?<Address>.+)").Match("山田太郎, どこか")
// 型のプロパティとして見えていたものはただのインデクサを使ったアクセスへ
let name = res.Groups.["Name"].Value
let address = res.Groups.["Address"].Value
F#ってこんな言語2 -- 生成型TP
・実際に型が生成される
・ディスク上にdllファイルが必要になる
・アセンブリ外部にも型が公開できる
F#ってこんな言語2 -- 生成型TPの例
// 実際に型が作られる
type Edmx = EdmxFile<"Model.edmx">
let context = new Edmx.Model.Entities(conStr)
query { for user in context.Users do
where (user.Age >= 20)
select user }
|> Seq.iter (fun user -> printfn "%s" user.Name)
(* Model.edmxを読み込み、メタデータを取得し、
メタデータをもとにdbmlファイル(!)を生成し、
SqlMetal.exeにdbmlファイルを食わせることでC#ファイルを生成(!?)。
最終的に生成されたC#ファイルをコンパイル(!?!?)している。 *)
F#の開発環境
・"An Atom Editor and Visual Studio Code package suite for
cross platform F# development."
・などなど
F#の開発環境
・Visual Studio
・Visual F# Tools(VS標準搭載)
・Visual F# Power Tools
・Ionide
・補完機能
・ツールチップ
・対話環境
F#の開発環境 - Visual F# Toolsの機能
・プロジェクトテンプレート
・参照の管理(NuGet含む)
・簡単なシンタックスハイライト
・リアルタイムのエラー表示(不完全)
・名前の変更リファクタリング
・インデントガイドの表示
・識別子の検索機能
F#の開発環境 - Visual F# Power Toolsの機能
・ドキュメンテーションコメント生成
・コード整形
・同一識別子のハイライト
・printfのプレースホルダーに対応する識別子のハイライト
・すべての参照箇所の検索機能
・未openな名前空間の解決機能
F#の開発環境 - Visual F# Power Toolsの機能2
・リッチなシンタックスハイライト
・未使用openのグレーアウト
・未使用宣言のグレーアウト
・フォルダー機能
・メタデータへの移動
・タスクリストコメント
F#の開発環境 - Visual F# Power Toolsの機能3
・コードの生成機能
・インターフェイスのメソッド群
・レコードのフィールド群
・判別共用体のケース
・Peek Definition
F#の開発環境 - Visual F# Power Toolsの機能4
・FSI用の参照の生成
・クイック情報パネル
・FSharpLint統合
・コードアウトライン機能
・同一識別子のハイライト
・コード整形
・対話環境
F#の開発環境 - Ionideの機能1
・補完機能
・ツールチップ
・シンタックスハイライト
・エラー表示
F#の開発環境 - Ionideの機能2
・プロジェクトテンプレート(F# Yeoman Generator統合)
・参照の管理(Paket統合)
・ビルド機能(FAKE統合)
F#の開発環境 - VS・・・
・VSそのままではいろいろつらい
・VFPTを導入するとか、別のIDEを使うことになる
・VFPTもIonideもGithubで開発されている
・言語開発者ではない人でもIDEの機能は作れる!
F#の開発環境を作るには
F#の開発環境を作るには - 色付け1
・キーワードにマッチしたら色を付ける?
・文字列の中にあるものは?
・文字列に色を付けたい場合は?
F#の開発環境を作るには - 色付け2
・コードを自分で構文解析して、トークン列からキーワード
を探して色を付ける?
・言語がバージョンアップしたら構文解析も更新?
・文脈に依存するキーワードは?
・TypeScriptではtypescriptServices.js
・F#ではFSharp.Compiler.Service (略称FCS)
F#の開発環境を作るには - 言語サービスの必要性
・色付け機能すら面倒
・言語処理系の機能に外部からアクセスできれば・・・
・それを実現するものが「言語サービス」
・C#/VBではRoslyn
・プロジェクトをまたいだ解析
・F# interactiveのホスティング
・F#コンパイラのホスティング
・ファイルシステムAPI
F#の開発環境を作るには - FCSでできること1
・ソースコードからトークン列への変換
・型なしASTの処理
・エディタサービス
・解決済みシンボルの解決
コードからトークン列への変換でできること
・簡単な色付けくらいならこれで
・この資料のF#コードもこの機能を使って色付けしている
・VFPTのTODOコメントの収集はこれを使っている
型なしASTの処理でできること
・もうちょっとリッチな色付けくらいならこれで
・コード整形
・(コードではなく)型なしASTを食うCompileメソッド
・型なしASTを変換したものをコンパイル、とかできる
エディタサービスでできること
・ツールチップ情報の取得
・補完候補の取得
・オーバーロード一覧の取得
解決済みシンボルの解決でできること
・リッチな色付け機能
・型なしAST + 解決済みシンボルで型付きASTの代替
・ローカルな名前の変更リファクタリング
プロジェクトをまたいだ解析でできること
・すべての参照の検索
・名前の変更リファクタリング
・などなど
F#の開発環境を作ろう
・F#の開発環境は自分で作れる
・自分でどんどん便利なツールを作っていきましょう!

F#の基礎(?)