えくせる
現実と戦う話
bleis-tift
August 24, 2013
自己紹介
@bleis / id:bleis-tift
なごやではたらくゆるふわ C#1.2er
好きな関数型言語は F#
Microsoft MVP for Visual F#
いよちゃんかわいいよいよちゃん
わたしの思う
な ご や
現実・・・
げ ん じ つ
Excel 方眼紙からは逃げられない。
げ ん じ つ
Excel方眼紙から目をそらす?
Excel は関数型言語だ!
目を覚ませ、目の前にあるのはた
だのExcelじゃない、方眼紙だ!
げ ん じ つ
Excel方眼紙と戦うための武器
VBA
COM
Excel-DNA
POI(NPOI)
Type Provider ← New!
型 プ ロ バ イ ダ ー
Type Provider?
F#3.0 からの新機能
コンパイル時計算のための仕組み
メタデータから型を生成する機能
例えば、DB のスキーマから型を作ったり
ネットワークから JSON を引っ張ってきて型を
作ったり
それってコードの自動生成でいいのでは?
TypeProviderとコードの自動生成の違い
コンパイルフェーズだけで完結できるか
バージョン管理上の問題
生成されたコードを含める?含めない?
基本的には含めない方がいい。でも、生成のた
めのツールをみんなが持ってるかどうかを考え
ると・・・
見せる必要のないコードを隠せる
T4 使うと見せる必要のないコードが大量に・・・
(例:LangExt 3000 行や 4000 行のファイルが・・・
図解TypeProvider
Type Provider
(¡ ¢£ に¦§¤)
©¥
あなたのコード
メタデータ

¨
 !
#
$
%
'()'0123
・直接(文字列とかで)渡す
・ローカルファイルから
読み込む
・ネットワークから
読み込む
・h4から読み込む
TypeProviderで型を提供されてみる
.
hoge
..
.
type DB = EdmxFileHoge.edmx
// DB 型を使ったコード
...
色々なTypeProvider
DB 系
EdmxFile
SqlEntityConnection
データ形式系
AppSettings (FSharpx)
XAML (FSharpx)
ExcelFile (FSharpx)
XmlProvider (FSharp.Data)
JsonProvider (FSharp.Data)
その他
Regex (FSharpx)
TypeScriptProvider (FunScript)
などなど。
参考: http://sergeytihon.wordpress.com/2013/08/05/
ExcelTypeProvider
Excel を操作するための TypeProvider
「名前」を設定した Excel ファイルを指定す
るか、
対象の範囲を別に指定する
読み込みオンリー
これじゃない・・・
ExcelTypeProviderのココがダメ!
「名前」が上手く使える Excel 方眼紙とか
ない
範囲だけ指定してうまく扱える Excel 方眼紙
とかない
Excel と範囲を指定するための単純な文字列
のみをメタデータとして使っており、柔軟性
がない
出来れば書き込みたい
こ れ は 普 通 の E x c e l ファイ ル の た め の T y p e P r o v i d e r だ・・・!
これで Excel 方眼紙に立ち向かうのは無理ぽ
どういうTypeProviderが欲しいのか
Excel 方眼紙は多種多様
ExcelTypeProvider が持っているような前提は置
けない
カスタマイズ可能なよう、メタデータは外部化
されているべき
納品物に名前情報とか埋め込んじゃ駄目なとこ
ろもあるかもしれませんしねー (白目
メタデータもある程度事前に検証したい
TypeProvider に渡して初めて記述ミスに気付く、
とかは避けたい
ホスト言語 (F#) で書かれていると嬉しい
作りました (作りかけ)。
その名も・・・
え く せ る 方 眼 紙 タ イ プ プ ロ バ イ ダ ー
ExcelHouganshiTypeProvider!
.
コードの入手方法
..
.git clone https://github.com/RealWorlds/ExcelHouganshi.TypeProvider.git
一部の dll を GAC に登録してるので、VS は管理者
で開いてビルドしてください。
デモ
仕組み(サンプルの構成)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
ExcelHouganshi.TypeProvider.Data
ExcelBook
ExcelSheet
ExcelCell
Definition
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
こいつ
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
...
[TypeProvider]
type Houganshi (...) as this =
inherit TypeProviderForNamespaces ()
...
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
...
[TypeProvider]
type Houganshi (...) as this =
inherit TypeProviderForNamespaces ()
...
ファイル読み込み
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
...
[TypeProvider]
type Houganshi (...) as this =
inherit TypeProviderForNamespaces ()
...
ファイル読み込み
...
[HougenDefinition]
let myHouganshi =
[
Define.field Title {
Type = StringField
Sheet = Sheet1
Address = A1
}
Define.field SubTitle {
Type = StringField
Sheet = Sheet1
Address = A2
}
]
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
...
[TypeProvider]
type Houganshi (...) as this =
inherit TypeProviderForNamespaces ()
...
ファイル読み込み
...
[HougenDefinition]
let myHouganshi =
[
Define.field Title {
Type = StringField
Sheet = Sheet1
Address = A1
}
Define.field SubTitle {
Type = StringField
Sheet = Sheet1
Address = A2
}
] 一時フォルダ
dll
コンパイル
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
一時フォルダ
dll
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
一時フォルダ
dll
ロード
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
一時フォルダ
dll
ロード
メタデータから
型の生成
仕組み(コンパイル時の挙動)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
...
type MyHouganshi = HouganshiDef.fs
...
一時フォルダ
dll
ロード
メタデータから
型の生成
型の提供
仕組み(実行時に必要なもの)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
一時フォルダ
dll
ExcelHouganshi.TypeProvider.Data
ExcelBook
ExcelSheet
ExcelCell
Definition
仕組み(実行時に必要なもの)
Sample
Def.fs
Program.fs
ExcelHouganshi.TypeProvider
Houganshi
ExcelFile
一時フォルダ
dll
ExcelHouganshi.TypeProvider.Data
ExcelBook
ExcelSheet
ExcelCell
Definition
できること
扱う Excel 方眼紙の形式のユーザ定義
ユーザ定義部分の外部化
ユーザ定義の F#による記述
セルの値の読み書き
できないこと
非 Windows 環境の救済
でも、内部では NPOI 使ってるし、mono で行け
るかも?
VS2010 以前 (2010 含む) ユーザの救済
TypeProvider が使えるのが VS2012 移行に搭載さ
れている F#
VS を入れなくても F#は使えるので・・・
その他機能的な問題
セル以外を扱う (今後実装予定)
なぜか VS を再起動しないとインテリセンスが反
応しない
GAC に登録せずに動かす
まとめ
Excel 方眼紙を倒す可能性を秘めた武器を手
に入れたかもしれない
でもまだ負けてる
いつか Excel 方眼紙に勝ちたい
そもそも、この方向で進んで勝てるのか?という
話はある (ぉ
おまけ
TypeProviderのつくりかた
1. F#3.0 Sample Pack 内の
ProvidedTypes-head.fs をコピーしてくる
必須ではないが、全部自分で実装するのはだるい
色々なものが internal なので、プロジェクトにコ
ピーするのがいい
2. ProvidedTypeDefinition オブジェクト (提供す
る型) を生成する
3. 上で作ったオブジェクトにメソッドやプロパ
ティなどを生やす
4. AddNamespace を呼び出す
3 を頑張る感じ
TypeProviderのデバッグ
同一ソリューション内にデバッグ用プロジェクト
を作ると、dll を握りっぱなしになってビルドでき
なくなる
ソリューションを分ける
fsproj の PropertyGroup に以下の定義を追加
する
.
.
StartArgumentsSample.sln/StartArguments
StartActionProgram/StartAction
StartProgram$(DevEnvDir)devenv.exe/StartProgram
StartWorkingDirectory$(SolutionDir)/StartWorkingDirectory
これでデバッグ起動すると、新しい VS が立ち上
がってデバッグ可能に!
小技
ProvidedTypeDefinition の HideObjectMethods
プロパティを true に設定すると、obj のメ
ソッドが隠れる
コンパイル時コンパイルがかなりの回数走る
ので、Git 方式でファイル存在チェックを導入
全部式木で書くのはだるいので、書ける部分
はコード引用符を使った
はまったところ(その1)
コンパイル時コンパイルは問題がいっぱい
F#CodeDom が古い
→ NuGet から取ってくるのを諦め、ソリュー
ション内に追加して修正
インメモリでやろうとするとエラーになる
→ 一時フォルダに出力するようにした
生成するアセンブリが他のアセンブリに依存
していると、実行時エラーが発生する
→ アセンブリを分割して、依存を無くした
Data アセンブリが見つからない
→ Data アセンブリを GAC 登録
はまったところ(その2)
式木は問題がいっぱい
コード引用符の外側の変数が、使えないこと
がある
→ 式木を自分で構築すればできるかも?面倒
なので色々諦めた
スプライス (アンクォート) の際に Type オブ
ジェクトで型指定できない
→ コード引用符を諦めて、式木を自分で組
み立てて回避
式木上の型と、実行時の型が合わない
→ がんばって型を合わせる
はまったところ(その3)
時間がない
仕事が!多い!!!
→ がんばって仕事を終わらせる
使える言語が C#1.2
→ OOPって、楽しいですよね・・・
でも、今回はかなーり余裕をもって資料作れま
した!

現実(えくせる)と戦う話