SmlSharpContribについて
これはML Advent Calendar 2015と関数プログラミングAdvent Calendar 2015の一日目の記事です。
えすえむえるしゃーぷって?
関数プログラミング交流会で調査した感じだと、知っている人は増えつつあるがユーザはまだそんなにといったところなのかもしれません。
SmlSharpContribとは
ざっくりいうと「準標準パッーケージを作ろう」みたいな感じでしょうか。
- データ構造
- 便利関数
- エンコーダデコーダ
が現状で提供されている機能です。
「え、その型すら標準にないの?」などと言ってはいけません。
ライブラリを作るという話になった経緯
2015年の2月頃に、大阪の知り合いが仕事の都合で名古屋に来るということで何名かでご飯を食べに行きました。 そこでなぜか(話の流れは忘れた)みずなんとかさんとぶれなんとかさんが「SML#の準標準ライブラリが欲しい」と言い出し、何人かを巻き込む形で始動しました。
なんか開発止まってるようにみえるけど…
みなさんお忙しいですからね、決して興味がなくなったとかいうわけではないはず…ええきっと。
もみあげはなにをしたの?
パーサコンビネータ、JSONパーサなどを作ってました。 XMLパーサも実装しようとしていましたが体力切れで絶賛放置中…。
おわりに
SML#は楽しい(はずな)ので、みなさんもSmlSharpContribに貢献するという形でSML#を触ってみませんか?
"ValueWithName"や"Auto-Quotation of Arguments at Method Calls"を使って変数名や関数名を取得する #FsAdvent
この記事はF# Advent Calendar 2015の一日目の記事です。
Expr.ValueWithName
の話
以下のようなコードがあるとします。
let f a = <@ a @> let hoge = "Hi!" f hoge
これはどう表示されるでしょうか?
F# 3系までは以下のとおり(VS2013のF# interactiveで確認したのでちょっと正確な言い方ではないかも)。
Value ("Hi!") {CustomAttributes = []; Raw = ...; Type = System.String;}
F# 4.0からは次のようになります(VS2015のF# interactiveで確認したのでちょっと正確な言い方ではないかも)。
ValueWithName ("Hi!", a) {CustomAttributes = []; Raw = ...; Type = System.String;}
Expr.ValueWithName
となり、束縛名が取れるようになりました。
ReflectedDefinitionとメソッド呼び出しでの引数の暗黙的なauto-quotation
上記ドキュメントを読めばわかるとおり
static member Plot([<ReflectedDefinition>] values:Expr<int>) = ...
と定義してあげると
Chart.Plot(f x + f y)
このようなコードは下記の形に暗黙的に変換されます。
Chart.Plot(<@ f x + f y @>)
ReflectedDefinitionのIncludeValueとExpr.WithValue
先ほどのドキュメントにも書かれているとおり
static member Plot([<ReflectedDefinition(true)>] values:Expr<X>) = ...
IncludeValueをtrueにすることで、quotationに変換する際に
Chart.Plot(Expr.WithValue(f x + f y, <@ f x + f y @>))
Expr.WithValue(obj, Expr)
の形に変換されるようになります。
Persimmon.Driedによる利用例
いきなり利用例の話…の前に、ちょっとした問題提起から。
今年に入って実装を進めているライブラリの一つにPersimmon.Driedというものがありますが、下記のブログにも述べられているとおり弱点が存在します。
Persimmon.Dried で性質をチェックする — a wandering wolf
今回の話に関連する部分を以下に引用します。
1つは apply した先でテストに失敗した時に、どの apply で失敗したかが明確ではない点です。大体はどこで失敗したか予想はつきますが、1つの property ブロックに複数の apply を入れていると、失敗結果から自明には分かりません。どの Prop が失敗したか、名前が分かるととても捗りますね。
具体的なコードはFuncyというライブラリのテストがわかりやすいと思います。
Persimmon.DriedのPropnにはラベルをつける機能があるのですが、今回のように変数束縛するのであれば変数名からいい感じに名前を取得して重複させないようにしたいですね? というわけで先ほど紹介した機能の出番となります。
成果物
コードは下記で公開しています。
ReflectedDefinition、WithValue, NameWithValueを使って名前を取得する
まず、既存のPropertyBuilderには手を入れたくないので別ライブラリとしてコンピュテーション式のビルダーをラップします。 その後、該当部分のメソッド引数にReflectedDefinitionをつけていきます。
// 定義部分だけてきとーに抜粋 member __.Apply<'T, 'U when 'U :> Prop>(s: PropertiesState<'T>, [<ReflectedDefinition(true)>] expr: Expr<'U>) = member __.ApplyReturn(s, [<ReflectedDefinition(true)>] expr: Expr<Prop<'T>>) =
使う側はモジュールを一つオープンするだけで、変数名がラベルとして表示されるようになります。
実際に名前を取得する部分ですが
アクティブパターンを使ってひたすら地道に名前を取得しています。
また、引数の型をExpr<'T>
にしておけば値は'T
なことが確定するので、安心してWithValue
の第一引数やPropertyInfoで取得できるobjを'T
にダウンキャストできます。
おわりに
Expr は 4.0 になってさらなる可能性をもたらしてくれました。
これらの機能とコンピュテーション式を組み合わせると無限に悪巧みができそう有効活用ができそうなので、もっと使い倒してみたいところですね。
おわりにその2(追記)
Persimmonを実装しているプロジェクトのGitter日本語部屋があるので興味のある型はぜひ。
Scala.jsに対応したscodec-msgpackをリリースしました
この記事は予約投稿です。
id:xuwei さんが ささっと作業してくださったのでリリースしました。
https://github.com/pocketberserker/scodec-msgpack/tree/v0.4.1
v0.4.0はプロジェクトの設定ミスにより空のjarが降って来るだけなのでスルーしてください…。
なんでscala-jsに対応できたのか
- shapeless は Scala.js をサポートしている
- scodec-bits も Scala.js をサポートしている
- 依存している二つのライブラリが Scala.js をサポートしたので、 scodec-core も v1.8.3 から Scala.js をサポート開始
- scodec-msgpack は scodec-core のみに依存する、かつそんなに変なことはしていない
- よってプロジェクト設定とテスト部分のみコストをかければ問題なく対応可能
といった形です。 shapeless が Scala.js をサポートしているのはなんというか、すごいですね。 マクロ的とか楽に対応できるものなのだろうか…?
TypeClassを使うようにした
ライブラリを作っておいてアレですが、私自身がscodec-msgpackを使っているというわけではないのでテキトーでいいかなと思ってメンテナンスをさぼり気味でした。
しかし、下記issueがきたので
Make primitive `Serialize`s implicit · Issue #8 · pocketberserker/scodec-msgpack · GitHub
重い腰をあげてimplicitな形式に変更しました。
変更ついでにshapeless.TypeClass
も使うようにしたのでそれなりに自動生成できます。
インスタンス増やさないといけないのは…ぼちぼちやろうと思います。
その他
Elm の automaton を F# に移植した
おはようございます、ライブラリ移植するマンです。
つい先日、関数型ストリーム処理勉強会 - connpassという勉強会がありましたねというタイミングで、ElmのFRPライブラリが情報網にひっかかったので移植しました。
https://github.com/evancz/automaton
automaton is 何
ここでは "Arrowized FRP の実装の一つ"、という一言で終わらせてしまいます。 詳しくはリンク先のコード見たり論文読みましょう。
移植コード
https://github.com/pocketberserker/FSharp.Automaton
もう少し名前ひねるべき、という話もありますがまーそこはリスペクトということで。
雑多な話
- なんで Elm のライブラリ?
- higher kinded types をサポートしていないので移植しやすい
- Arrow を明示しているわけではないので移植しやすい
- Elm の Signal を .NET の System.IObservable で読み替えれば移植が楽そうだった
- 別に移植しなくても System.IObservable とか Rx でいいじゃない
- 趣味の問題
- テストは?
- あとでかく(ダメじゃん)
- サンプルコードは?
- あとでかく
Elixir入門するついでにelixir-supervisordというライブラリを作った
だいたいのことはErlangでいいんじゃないかなと思いつつ、まー触ってみないことには何とも言えないよねというのもあり、今回重い腰をようやくあげた。
触り始めて一週間。
ついでにライブラリ作った
https://hex.pm/packages/supervisord
supervisordのXMLRPC叩くだけの簡単なライブラリを作った。 supervisorという名前の影響で検索しづらい…
Elixir とか Phoenixとかの雑感
まだ一週間だからなんともではあるが
- パイプライン演算子、第一引数が対象なのかー的な
- dialyzerなしで使ったらやはりつらい
- パターンマッチがある分いくらかRubyとかより安心感あるけど、それでもね
- でもdialyzer重いんだよなーあーうーとか言ってみる
- Phoenix、Railsぽいだけはあるなーと
- ElixirとPhoenix触り始めて一日くらいで最低限の目的を達成できたので
- とはいえ外れたことやろうとすると苦労するんだろうなぁ…
- Phoenixが標準にしてるbrunchつらい(JavaScriptじゃないか!という突っ込みはなしで)
- Erlang OTPべんきょーしておいてよかった
- relxからのexrmとか、rebar3触ってからのmixとか、わりとさらっと入れる気がする
次の目標はマクロかな…どの言語でも黒魔術系苦手なので手になじむかびみょーだけど…
Persimmonはユニットテストを分散実行する夢をみるか?
- みるかもしれない。
どういうこと?
かいつまんで問題を説明すると
- PersimmonというF#用テスティングフレームワークが存在する
- PersimmonでもRRRSpecやtest_queueみたいに分散実行したいね?
- Persimmonでのテスト実行の入力はdll
- 単純に転送するだけだとdllがロードできずに死ぬ
- どうしよう
- 案1. テストオブジェクトをシリアライズする?
- そもそもテストという"関数"をシリアライズできるのか?
- 案2. 各実行サーバにプロジェクトコードをsyncしてコンパイル、一部実行
という話。
今回採用したもの: 案1
コードというか題材というか
https://github.com/persimmon-projects/Persimmon.Ripe/tree/fee25ceabae567cb21e110fe2df2b4f07b72286c
テストオブジェクトのシリアライズ、assemblyロード
別サーバでテストを実行するためには、テストオブジェクトに関連するassemblyをロードする必要がある。 仮にロードしないでテストを実行した場合は例外投げてテストに失敗する。
しかしどうやってロードするかね、という話の段階でVagabondの出番となる。
https://github.com/nessos/Vagabond
このライブラリはリモート環境でAssemblyをロードしたり色々できる優れものである。 また、通信することを想定してFsPicklerというシリアライザ*1を用いてオブジェクトをシリアライズする。
現時点でのPersimmn.Ripeは、Vagabondを使ってAssemblyやテストをRabbitMQ越しにやり取りするライブラリを提供している。
- 入力のdll群をロードしてテストオブジェクト一覧を取得する
- ここまでは通常のPersimmonと同じ
- テストオブジェクトに関連するAssemblyをVagabondで取得、RabbitMQに投げる
- サーバ側はテキトーに受け取ってAssemblyをロードする
- テストオブジェクトをシリアライズしてRabbitMQに投げる
- インターフェースだとキャストに失敗して原因もよくわからなかったので
TextWriter -> obj
でやり取りしてる… - TextWriterを渡す理由は実行したテスト名を出力したいから
- インターフェースだとキャストに失敗して原因もよくわからなかったので
- 各サーバがメッセージをconsumeしてテスト実行、結果をRabbitMQに投げる
- 失敗したらエラーをメッセージとしてなげる
- 全体統括者がテスト結果を収集して、全部取得できたら結果表示
- エラーだったら規定回数リトライ、それでもダメなら自分で実行するとかもやってる
この方式のキモ
- Vagabondが行っているAssemblyの解析とロード
- FsPicklerが行っている、IL Emitを前提としたシリアライズ
この二つのようなことができれば他の中間言語を持つやつでもわりとなんとかできそう。
課題
Vagabondが対応できる範囲でしか実行できない。 実際、RabbitMQではなくAzure Service Busに切り替えて試してみようとしたところ、VagabondがAssemblyをロードできず死ぬという現象が発生した。
案2を採用しなかった理由
- コンパイルする環境整えるのつらくない?
- 全体統括者がWorkerとなるサーバ群を知らないといけないとかそこそこ面倒
- プロジェクトファイルのsyncだけでリソースもってかれそう
今後の予定とか
- VagabondでロードできるAssemblyを増やせないか試す
- AMQP以外のものにも対応させる
- 例えばアクターとか
- ちょっと気になっているRubyのtest_queueさんについて調べる
- Scalaで似たようなことができないか考える
*1:こっちもnessos製
#fsharp 用テスティングフレームワーク Persimmon 1.0.0 をリリースしました
https://github.com/persimmon-projects/Persimmon/releases/tag/1.0.0
https://github.com/persimmon-projects/Persimmon.Dried/releases/tag/1.0.0
https://github.com/persimmon-projects/FAKE.Persimmon/releases/tag/1.0.0
Testing Framework Meetingで話にだしてたやつの F# のほうです。
first commit 一年からそろそろ一年だし、取り急ぎ入れたいものとかもなかったし、いつまでもbetaなのは微妙な気持ちになるので思い切ってリリースしました。
Persimmon 自体には デモプロジェクトがあったり Persimmon.Dried にはリポジトリ内にサンプルがあるので、使い方はそっち見てくださいということで。
姉妹ライブラリ
- https://github.com/scala-kennel/dog
- scalaでテストとアサーションを合成してみるフレームワーク
- こっちはテストケースがモナド
- このライブラリに関してはScalaMatsuri 2016で発表応募しているので気になるかつ投票権持ってる人はぜひ
今後
- VS拡張ェ…
- Persimmon.Dried
- いくつかの型がnullを生成していないので、nullも生成するようにする
- そのうえで、NonNullに楽に切り替えられるようにする
Persimmon使ってるプロジェクト
順不同