~スマートフォン用の表示で見るぐるぐる~この広告は、90日以上更新していないブログに表示しています。2013の9日目の記事です。リフレクション/式木に触れてみる」でした。時間がないうえにいろいろ問題もあって滞ってます・・・さて、今回は.NETの標準ライブラリと仲良くする話(もしくはBasis.Coreの紹介)です。Frameworkの資産が使えるため、標準状態で色々なことができます。Frameworkは関数型言語のために作られたわけではありません。Frameworkの標準ライブラリを使うと、F#の標準ライブラリとは違った使い心地を体験することになります。型推論との相性が悪い例えば、System.String型のToUpperメソッドを呼び出すとしましょう。str.ToUpper()このように、メソッド(や、プロパティ)しか呼び出さない場合、型推論が働いてくれないため、strの型を明示してあげる必要があります。C#などと違い、引数の位置以外でも型の指定は出来ますが、どこかで一回は明示する必要があります。Frameworkのメソッドはカリー化されていません。そのため、メソッドに対して部分適用できません。n)さらに、カリー化されていないので、パイプライン演算子との相性も良くないです。s.Substring(1)こう書くくらいなら、メソッドチェインしますよね。str.ToUpper().Substring(1)高階関数との相性が悪い一番厄介なのは、高階関数との相性が悪いことです。文字列のリストすべてを大文字にした新たなリストを作りたいとします。s.ToUpper())このように、ラムダ式を書く必要があります。インスタンスメソッドの場合はほぼ常にラムダ式を使うことになります。このままではつらい場合が多いのも事実なのです。これらが楽に行えると(個人的に)とても嬉しいのです。そのために、.NETの標準ライブラリとF#の橋渡しをするライブラリを作っています。それが、Basis.Coreです。「Basis.Core」というidでnuget.orgにも登録してありますので、簡単に使えます。Basis.Coreとは何であって何でないかBasis.Coreは、.NET(と、F#)の標準ライブラリで扱える範囲のものをより上手くF#で扱えるようにすることを最大の目標にしています。そのため、ライブラリとしてはあまり面白味のないものになっています。Basis.Coreは、以下のものではありません。様々な型を提供するライブラリではありません型プロバイダーを提供するライブラリではありません型クラスを提供するライブラリではありません.NETの標準ライブラリの範囲を大きく超える機能を提供するライブラリではありませんこれらのものではないため、このライブラリはあれもこれもと詰め込みすぎるようなことにはならないはずです。文字列を大文字化するために、型の明示が必要でした。str.ToUpper()Basis.CoreのStrモジュールを使うと、型推論が効くようになります。Str.toUpper基本的にはインスタンスメソッドの名前をlowerCamelにした名前になっています*1。部分適用Basis.Coreの関数はカリー化されているため、部分適用可能です。n)こう書いていたコードは、部分適用を使って書き直せます。パイプライン演算子と組み合わせることができます。高階関数に渡す際もラムダ式を書く必要がありません。Str.toUpperこうです。Basis.Coreで(まだ)できないことF#はメソッド以外ではオーバーロードが使えませんが、Basis.Coreはメソッドではなくモジュール関数で構築しています。そのため、標準ライブラリで用意されているオーバーロードには、それぞれ別名を付ける必要があります。System.StringのTrimには、char配列を取るバージョンがありますが、そちらにはtrimCharsという別名を付けています。現状では対応していないメソッドもあります。ToUpperはCultureInfoを取るバージョンがありますが、対応していません。個人的には使用頻度も高くないため、正直何か別名を与えて補完の候補を増やすのは避けたいところです。そのため、これらのメソッドには別名を与えるのではなく、別モジュールで定義するようにしようと考えています。Basis.Core.Culture名前空間にStrモジュールを置き、それをopenすることでCultureInfoを取る版のtrim等を使えるようにするのです。culture)このような感じで、Basis.Coreを発展させていこうと考えています。その他雑多なことNullableNullableって言うと、.NET的にはSystem.Nullable構造体のことを指すと思います。これってより正しくはNullableValueとかNullableValueTypeとかすべきだったものですよね。参照型はNullableなんてものに頼らずにnullが突っ込めるわけですし。Nullableモジュールを提供する場合にこれがすごく嫌な感じだったんです。Nullableって言ってるのに、参照型のnullは扱えないの?的な。これを解決するために、Basis.CoreではNullable.ValueTypeとNullable.ReferenceTypeという2つのモジュールを用意しました。nullを扱いにくくしつつサポートする、ということを実現しています。アクティブパターンも用意していますが、これも値型用のアクティブパターン(NullValとNonNullVal)と参照型用のアクティブパターン(NullRefとNonNullRef)の2つを提供しています。最初の方で、Basis.Coreは、.NET(と、F#)の標準ライブラリで扱える範囲のものをより上手くF#で扱えるようにすることを最大の目標にしています。書きましたが、.NETの標準ライブラリにもF#の標準ライブラリにもない型を提供している、例外t的なものがあります。それがResult型です。Result型は、成功するかもしれないし失敗するかもしれない処理の結果として使える型です。書くと、Optionと同じようなものに感じますが、実際やりたいことは同じことです。Optionの場合、失敗側に原因を持たせることができません。これを持たせるようにできるようにしたのがResult型です。実は、F#にはChoiceという型があり、これに対するアクティブパターンや型の別名を与えることでResult型の代わりにすることもできます。実際に、他のF#のライブラリではそうしていることがほとんどのようです。Choiceではどの選択肢の重みも同じイメージを受けるのです。それに対して、Resultという名前は何らかの結果、それも成功側に重点を置くという主張を型名によって行うことができます。このメリットが大きいと感じるため、Choiceを使わずにResultという型を提供しています。getOr/getOrElse/getOr'OptionとResultに対して、getOr/getOrElse/getOr'という3つのよく似た関数を提供しています。他の言語から見た場合はGetOrElseになります。F#は正格評価言語のため、デフォルト値は常に計算されてしまいます。"empty"これでは駄目な場合があるので、getOrElseというバリエーションがあります。こちらは、デフォルト値そのものを受け取るのではなく、それを関数で包んで受け取ります。そのため、値の計算を遅らせることができます。conStr)VBのOrが短絡評価されず、OrElseが短絡評価されることを参考に語彙を選んでいます。バリエーションとして、関数ではなくLazy<'T>を受け取るバージョンを用意しています。F#ではLazyはlazyキーワードで作ることができます。getOr'に渡す場合はほぼその場で値を作るだろう、との判断から、getOr'という名前にしました。CompiledNameの方はGetOrElseとしました。この選択が正しかったのかという自信はありません。そもそも、Lazy版を提供しない、という選択肢もあったわけですし・・・コンピュテーション式みんな大好きコンピュテーション式ですが、Basis.CoreでもOptionとResultに対するコンピュテーション式を提供しています。独特なところを上げると、returnやreturn!で必ずコンピュテーション式から抜け出せるFailure側用のコンピュテーション式も用意している"ゼロ値"を与えることで、通常はResultで用意できないwhileやforに対応しているところです。なんだかなぁ、なものになってしまいます。実は今日までバグがあって、NoneやFailureをreturn!してもコンピュテーション式から抜け出せませんでした。残念ながら時間切れでした。ビルダーが状態を持つのではなく、状態を引数で引き回すことで解決しています。あとの2つはあまり面白味はないですね。さんのアクティブパターンに関する記事のようです。2015の17日目の記事です。2014の5日目の記事です。...2013-05-30LangExtでのOptionの設計このエントリの最新版はGithubにあります。(1)検索はてなブログをはじめよう!bleis-tiftさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。