継続を利用してAsyncコンピュテーション式を実装できるか試す
Combine Deep Dives - ぐるぐる~ という記事にこういう文章があります。
このあたりを解決するために、Stateを使ったり継続を使ったりできるかもしれませんが、Async では未検証です。
そういえば検証したことはなかったなと思ったので、試してみました。
コード
コンパイルは通るしテストも通る、という代物は下記コードです。 ただし、テストは通ったけれど本当に非同期に動いているかどうかまでは検証していないというレベルです。
Option、Listの実装と異なる部分
OptionやListでの実装は、パターンマッチによって値を分解することで包まれていた値を取り出すことができるのでわりと簡単に実装できていました。
しかしAsync
はパターンマッチで分解できません。
というわけで、とりあえず各メソッドでは関数をAsync
で返すようにします。
そしてRun
メソッドでは値を返したいのでasync.Return
を渡します。
ゼロ値の処遇
今回実装したAsyncBuilder
ではZero
メソッドを提供せず、AsyncWithZeroBuilder
ゼロ値を渡すようにしました。
が、既存のコンピュテーション式よりもAsyncBuilder
の表現力が落ちるためちょっと納得いってません。
本当は「Return
やReturnFrom
が呼び出されなければコンパイルエラー」というビルダークラスを作りたかったのですが、if then ce
というコンピュテーション式の変形においてce
とZero
の型が一致しなければならず、そこを通過しつつRun
メソッドのみコンパイルエラーになるような実装をついに導き出せませんでした…無念。
未検証の作戦として「Run
で返す値をAsync<'T -> Async<'U>>
のままにする」というものがあります。しかし、これはこれでAsync.RunSynchronous
やAsync.Start
などの多くのメソッドをラップする必要があるので悩みどころです。
まとめ
コンピュテーション式について考えると休日が吹き飛ぶの、つらい。
テスティングフレームワークとSemantic Versioningでなんか考えた
タイトルが釣りっぽくなっていてすみません。
寝起きにぼーっと考えていたら疑問に思ったけど、チラシの裏がないのでここに投げておきます。
この記事は疑問を書いて投げっぱなしにするので解などはかかれていません
Semantic Versioning
semver警察という用語もあるとかないとか。
Evolve slowly
最後にこの話をきいたのはTestingFrameworkMeetingのid:t-wadaさんの資料だったはず。
http://twada.herokuapp.com/presentations/testing_framework_meeting/testing_framework_meeting.html#8
- Evolve slowly (テストコードは利用者の投資の結果そのものなので、その投資が早いサイクルで無駄になることはない、という安心を与えなければならない)
そのままですね。
ユーザはコードを変更しなくてもいいけど…みたいな話?
- ユーザはコードを変更しなくてもコンパイルが通る変更
- しかし互換は崩れる
こういう修正をする必要があったとき、semverに従えばメジャーバージョンを上げる必要があると思います。
で、開発者側としてはバグ修正なのでユーザに最新のバージョンを使って欲しいが、ユーザからは破壊的変更をバンバン行っているように見えるのでEvolve slowlyには反しているんじゃないか、みたいに思えなくもないというか。
いやまぁ、Change log読もうの一言で済むといえばその通りなのですが、メジャーバージョンがガンガンあがるってまだまだわりと抵抗あるんじゃないかなと思う次第です。 テスティングフレームワークなら余計にそう思ったりするのでは、とか。
一旦保留
ということを寝起きで考えましたが考えすぎなのかもしれないし眠いので寝ます。 これを読んで「考えすぎだよ」って思った方はそう私に伝えてください。
PaketとFAKEを使うようにした理由とか
おはようございます。 たぶんこの時間帯は寝ているので、この記事はきっと予約投稿(どうでもいい)。
ここ数日、重い腰をあげて開発したりメンテしたりしているF#系ライブラリの一部でPaketとFAKEを使うようにしたり、最近の書き方に合わせた。
今回対象にしたのは下記のライブラリ。
https://github.com/persimmon-projects/Persimmon https://github.com/persimmon-projects/Persimmon.Dried https://github.com/pocketberserker/FAKE.GitBook https://github.com/persimmon-projects/Persimmon.Dried.Quotations https://github.com/pocketberserker/FAKE.GitBook
基本はProjectScaffoldを参考に、各プロジェクトごとに細かい変更をしている。 ProjectScaffoldはパブリックドメインなので遠慮なく参考にしましょう。
細かい嵌りどころ
- そもそもディレクトリ構成が全然違うものは合わせるのに時間がかかる
frameworkAssembly
にFSharp.Core
が設定されているライブラリを参照すると、思いもよらないFSharp.Core
の重複参照を招く- しかもエラー場所がわかりづらい…
- Paketは今のところ回避手段がない
paket install
やpaket update
で毎回この問題にぶつかるため、温かみのある手作業をする必要がある
- nuspecでできることがすべてpaket.templateでできるわけではない
- バージョン参照とか現状無理
- とはいえ、nuspecよりもpaket.templateのほうが楽な部分もあるのでどっちもどっち
なぜPaketを使うようにしたか
そこそこ前からF#界隈だとデファクトスタンダードだったこいつを、なんで去年あたりからようやく使い始めたのかというと
- いきなりVisual Studio上でビルドしてもちゃんと依存パッケージをダウンロードしてくれるようになった
- 正直これが大きい
- 以前はコマンド叩いてからVS上でビルド…という工程がつらくて使わなかったというのが原因の7割
- Paket.VisualStudioができた
- とはいえGUIを一回も使ったことがない…
- Visual Studio 2015からnugetからのrestoreを設定してもnuget.exeが入ってこなくなった
- 移行理由の3割
- TravisCIとかを考えるとプロジェクト同梱のほうが楽だなと感じている
- これは人それぞれだと思う
そういえば最近、group
によって依存パッケージを細かく分離できるようになったようだ。
おかげでProjectScaffold内の各種pathも変更されていて、なし崩し的に対応する必要がでたがそこはまた別の話。
とはいえ、NuGetで困らないレベルのライブラリ群は引き続きNuGetでやるつもりである。
なぜFAKEを使うようにしたか
DSLが不評だったり若干もっさりするなど、色々言われていたビルドツールFAKEさん。 私は消耗したくないのでPowerShellやbashで書けばいいや(それはそれで消耗するのでは、とか突っ込みはなしで)とかずっと思っていましたが、まぁ色々とあるのですよ…。
- 別言語のビルドツールを使っていたら、抵抗するのがむなしくなった
- npm(+gulp)、sbt、gradle、rebar、mix、etc…
- あれ、どれも大差ないじゃんという気持ちに(もちろん人によって異論はあるだろう)
- 各言語のデファクトスタンダードを使っておけば数年は死なないだろうという結論に至った
- Paketによって敷居が若干下がった?
- NuGet時代はどこにpackage.configを置くか悩んだ
- 悩んだ結果、使わなかった
- Gitへのコミットやその他の操作をPowerShellやbashでひたすら頑張ることの限界
- 消耗し始めた
- PowerShellやbashに強いマンではないので…
特に積極的な理由はないという…すみません。
まとめ
デファクトスタンダードには巻かれよう。
そのうち強い人たちがもっといいものを作ってくれる。
そういう未来を信じるんだ!
最近使っている F# のライブラリやツール
下記のF#版です。
最近使っているScalaのライブラリ - pocketberserkerの爆走
ここ1年くらいのものを対象にしています。
といってもそんなに数はない…。
ライブラリ
自分が開発に関わっているものは除外しています。
FSharp.Data
https://github.com/fsharp/FSharp.Data
まぁ、FSharp.Data.JsonTypeProviderばかり使っているわけですが…。
FsRandom
https://github.com/kos59125/FsRandom
Persimmon.DriedがFsRandomに依存している関係上、一番お世話になっているかもしれない。
FsCheck
https://github.com/fscheck/FsCheck
新しく作るときはPersimmonシリーズを使っているのですが、既存のライブラリや他の人が作っているライブラリでは使っているので。
FsUnit
https://github.com/fsprojects/FsUnit
FsCheckとだいたい同じモチベーションで使っている。
FsPickler
https://github.com/nessos/FsPickler
関数のシリアライズのお供に。
FsYaml
https://github.com/bleis-tift/FsYaml
他のライブラリを探すのが面倒なのでなんとなく使っている。
FSharp.TypeProviders.StarterPack
https://github.com/fsprojects/FSharp.TypeProviders.StarterPack
TypeProviderのお供に。
FSharp.Formatting
https://github.com/tpetricek/FSharp.Formatting
ドキュメントでひたすらお世話になっている。
FSharp.Quotations.Evaluator
https://github.com/fsprojects/FSharp.Quotations.Evaluator
使っているというかforkしているというか。。。
ツール
わりとあった。
Paket
https://github.com/fsprojects/Paket
VS2015あたりからnugetの実行ファイルがくっついてこないのでこっちに切り替えた。 FAKEもセットで使うことが多い。
VS拡張の登場によって以前ほど抵抗がなくなった。
https://github.com/fsprojects/Paket.VisualStudio
FAKE
https://github.com/fsharp/FAKE
nugetにpublishする必要があるライブラリでは使っている。 が、あまり好きではない(AutoOpenするスタイルが……)。
FsReveal
https://github.com/fsprojects/FsReveal
F# のコードをのせる必要があるスライドを作成する時にお試しで使ってみている。
VisualFSharpPowerTools
https://github.com/fsprojects/VisualFSharpPowerTools
略してVFPT。Visual Studioで F# 書くならほぼ必須。だが重い。
使ってないけど有名そうなもの
一応紹介。
FsControl, FSharpPlus
https://github.com/gmpl/FsControl
https://github.com/gmpl/FSharpPlus
型クラス系のアレ。
FParsec
https://bitbucket.org/fparsec/main
実はちゃんと使ったことがない(業務でもたまたま遭遇しなかった)。
ProjectScaffold
https://github.com/fsprojects/ProjectScaffold
スクリプトは参考にさせてもらいつつ、しかしこれを使ってプロジェクトを作成したことはない……。
FSharpLint
https://github.com/fsprojects/FSharpLint
VFPTでの設定は切っているのでお世話になっていない……。
FSharp.Compiler.Service
https://github.com/fsharp/FSharp.Compiler.Service
間接的にお世話になっているが、実際に導入したことはなかったりする。 なかなか機会に恵まれない……。
終わりに一言
多分他の人とはラインナップが全然違うだろうなぁ……。
FAKEとgitbookとAppVeyorを組み合わせて、自動でビルドして生成したhtmlをgh-pagesブランチにcommitとpush
あけましておめでとうございます。 年末年始の息抜きでやってたものをまとめておきます。
gitbookとtutとtravis-ciを組み合わせて、自動でビルドして生成したhtmlをgh-pagesブランチにcommitとpush - scalaとか・・・
これを F# でやろうという話です。
FAKEとかgitbookとかAppVeyorの説明はしません。
FAKE.GitBookに関しては試作段階の話を書きました。 なおFAKE.GitBookはちょっと手直しした版をnugetに公開しています。 ただてきとーに作っているので今後もAPIが変わりそうです……。
GitBookを出力するためのFAKE拡張の試作品を作った #FsAdvent - pocketberserkerの爆走
というわけで、成果物が下記になります。
- https://github.com/pocketberserker/FAKE.GitBook.Sample
AppVeyorでのgit push権限周りに関してはこのページの方法を使いました。 本当はsshのやつにしたほうが良いのでしょうが、体力切れのため後日対応で……。
- 肝心のpushに関してはFAKEに丸投げしました。最初powershellで書いてたけどだんだん面倒になった……
- chocolateyでcalibreをインストールしていますが、そのままではパスが通ってないのでpdf生成時にコマンドがないと言って怒られます。なのでパスを追加で設定します。
- 元ネタ記事のほうではTextLintにも対応されていますが、こちらではまだ入れていません。そのうち入れます。
- 記事のタイトルで"htmlをgh-pagesブランチにcommitとpush"とか言ってますが、それ以外にもpdfとepubを生成してartifactsとして保存しています。
気が向いたらドキュメントなり資料なりを書いていきたい……
2015年簡易振り返り
書いておかないと忘れるけどもう時間がないので簡易版。
生活
- F# MVPから.NET MVPになった
- MVPらしい活動をしていたかどうかは微妙なところだが、なんかやってはいた気がする
- 転職した
- 転職の際にScalaMatsuriの情報を使わせてもらったお礼にと思ってインタビューを受けたが、インタビューを受けるのはこれが初だったのでわりと緊張した
- やはり東京にいると便利だなと思うことが多い
- しかし地元九州からさらに遠ざかってしまった…移動が面倒だったので今年は帰省していない
- 生活時間が順調に狂った
- ただし、転職以前に感じていた寝起きのつらさ的なストレスが消えたのでこれはこれで良かったのかもしれない
- 年末になってようやく引っ越し貧乏から脱出しつつある
- ゲームはコンスタントに買って消化していた気がする
- 去年からの積みゲーがそのままになっている問題…
- なんだかんだひと月一記事以上ブログ書いてたらしい
言語
- F#: ほぼプライベートオンリーだけどなぜかわりと触ってた
- Scala: ほぼプライベートオンリーだけど(ry
- TypeScript: 諸事情で手を出した
- Elixir: 諸事情で手を出した
- Erlang: ちょっとだけ書いたけど思った以上に書かなかった
- SML#: なぜか一時期書いてた
- C++: 諸事情で書いた
- Rust: nomを触るためにちょっと学んだ
- Haskell: 読む力は上がったが一切書いた記憶がない
Rustを本腰入れてやりたい気もしつつ、Idrisに挑戦したい気もしつつ、Coqから目を背けないほうがいいのか…色々考えても結局なるようにしかならないので考えるのをやめよう。 来年のことは来年の私が頑張ってくれるはずだ。
ライブラリは産廃なものと形になったもので半々といったところ。 まぁ、使うことを目的としていないのでこんなものではないだろうか。
イベントとか
会社のセミナールームが使えることに味を占めて色々開催したりお手伝いしていた気がする。
- Lens & Prism
- F#談話室(これは一回会場手配しただけだけど
- 関数型Scalaの集い
- 関数プログラミング交流会
- Testing Framework Meeting
- 関数型ストリーム処理勉強会(これは相談を受けて開催したやつ)
- Oleg勉強会
個人的には、知らないことが何か知れたという点で非常に満足度の高いものだった。
あと、なんだかんだで発表していたようだ。
- なごやかJava ゆるふわテストツール編
- 2000年ごろのインターネットを懐かしむ会
- 富山合同勉強会 .NET & Java
- モナド基礎勉強会 vol.2
- 関数型Scalaの集い
- PEGと構文解析に関するアレコレの勉強会 Vol.1
- 関数プログラミング交流会
- Testing Framework Meeting
ペースは落ちるかもしれないが、何回かは発表したいところだ。
.NET系の勉強会に顔を出したいと思いつつなかなか足を運べていないのでなんとかしたい。
締め
気の向くままに。
お前もnullにしてやろうか! #FsAdvent
この記事はF# Advent Calendar 2015の31日目の記事です。
ガス欠なので役に立たないネタでお茶を濁します。
Noneはnullと解釈できる
F#erの皆様はたいていprintf "%A" None
を実行して<null>
と表示されることに落胆したことがあるのではないでしょうか。
私は落胆しました。
同じようなことをやってみる
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] type A<'T> = B | C of 'T with [<CompilationRepresentation(CompilationRepresentationFlags.Instance)>] member this.Value = match this with | C a -> a | B -> failwith "oops!
CompilationRepresentationFlags.UseNullAsTrueValue
を指定することで、引数をとらない識別子をnullとして表現可能になります。
こいつを付けた状態でメンバーにCompilationRepresentationFlags.Instance
を付けなかったら、そのメンバーは静的にコンパイルされます。
使いどころは?
- .NETが絡む
- その判別共用体の中で引数をとらない識別子が一つのみ
- nullにしてもよいと思った場合
これがそろったら使うか…? くらいの認識です。 ぶっちゃけ使うことはないだろうと思っています。
気を付けるべきとき
自分は使わないとはいえ、どのライブラリも使わないということは言えないので、対処してあげる必要があったりします。
ぱっと思いつく罠にはまるパターンはPretty Printerですね。
あとは box
したときにやらかしそうとかですかね。
結論
使うな。だが注意せよ。
追記
こうしてnullに表現可能になった識別子は、コンパイルしたらUnchecked.defaultof
でnullではなく代わりにunion caseのほうが使われるみたいですね。
F# Interactiveではnullが返ってきたので、コンパイラが色々やっている模様。