|
検索
タグ
ASP.NET
.NET
ASP.NET MVC
F#
Visual Studio
Azure
ASP.NET Core
ライトニングトーク
Plone
Selenium
AJAX
C#
jQuery
JavaScript
SQL Server
ADO.NET Entity Framework
WebMatrix
LINQ
EFCore
TypeScript
カテゴリ
最新の記事
最新のコメント
記事ランキング
最新のトラックバック
以前の記事
2026年 01月 2025年 12月 2025年 11月 2025年 10月 2025年 09月 2025年 08月 2025年 07月 2025年 06月 2025年 05月 2025年 04月 2025年 03月 2025年 02月 2024年 12月 2024年 11月 2024年 10月 2024年 09月 2024年 08月 2024年 04月 2024年 03月 2024年 02月 2024年 01月 2023年 12月 2023年 11月 2023年 10月 2023年 09月 2023年 08月 2023年 07月 2023年 06月 2023年 05月 2023年 04月 2023年 03月 2023年 02月 2023年 01月 2022年 12月 2022年 11月 2022年 10月 2022年 09月 2022年 08月 2022年 07月 2022年 06月 2022年 05月 2022年 04月 2022年 03月 2022年 02月 2022年 01月 2021年 12月 2021年 11月 2021年 10月 2021年 09月 2021年 08月 2021年 07月 2021年 06月 2021年 05月 2021年 04月 2021年 03月 2021年 02月 2021年 01月 2020年 12月 2020年 11月 2020年 10月 2020年 09月 2020年 08月 2020年 07月 2020年 06月 2020年 05月 2020年 04月 2020年 03月 2020年 02月 2020年 01月 2019年 12月 2019年 11月 2019年 10月 2019年 09月 2019年 08月 2019年 07月 2019年 06月 2019年 05月 2019年 04月 2019年 03月 2019年 02月 2019年 01月 2018年 12月 2018年 11月 2018年 10月 2018年 09月 2018年 08月 2018年 07月 2018年 06月 2018年 05月 2018年 04月 2018年 03月 2018年 02月 2018年 01月 2017年 12月 2017年 11月 2017年 10月 2017年 09月 2017年 08月 2017年 07月 2017年 06月 2017年 05月 2017年 04月 2017年 02月 2017年 01月 2016年 12月 2016年 11月 2016年 10月 2016年 09月 2016年 08月 2016年 07月 2016年 06月 2016年 05月 2016年 04月 2016年 03月 2016年 02月 2016年 01月 2015年 12月 2015年 11月 2015年 10月 2015年 09月 2015年 08月 2015年 07月 2015年 05月 2015年 04月 2015年 03月 2015年 02月 2015年 01月 2014年 12月 2014年 11月 2014年 10月 2014年 09月 2014年 08月 2014年 06月 2014年 04月 2014年 03月 2014年 02月 2014年 01月 2013年 12月 2013年 10月 2013年 09月 2013年 08月 2013年 07月 2013年 06月 2013年 05月 2013年 04月 2013年 03月 2013年 02月 2013年 01月 2012年 12月 2012年 11月 2012年 10月 2012年 09月 2012年 08月 2012年 07月 2012年 06月 2012年 05月 2012年 04月 2012年 03月 2012年 02月 2012年 01月 2011年 12月 2011年 11月 2011年 10月 2011年 09月 2011年 08月 2011年 07月 2011年 06月 2011年 05月 2011年 04月 2011年 03月 2011年 02月 2011年 01月 2010年 12月 2010年 11月 2010年 10月 2010年 09月 2010年 08月 2010年 07月 2010年 06月 2010年 05月 2010年 04月 2010年 03月 2010年 02月 2010年 01月 2009年 12月 2009年 10月 2009年 09月 2009年 07月 2009年 06月 2009年 05月 2009年 04月 2009年 03月 2009年 02月 2009年 01月 2008年 12月 2008年 11月 2008年 10月 2008年 09月 2008年 08月 2008年 07月 2008年 06月 2008年 05月 2008年 04月 2008年 03月 2008年 02月 2008年 01月 2007年 12月 2007年 11月 2007年 04月 2007年 03月 2007年 02月 2007年 01月 2006年 11月 2006年 10月 2006年 09月 2006年 08月 2006年 07月 |
2010年 05月 06日
ちょっと番外編。
前回までで、F# で Fizz-Buzz 問題を "わざわざ" アクティブパターンを使って "変則的に" 解くことをやってみたわけだが、やっぱり、普通に >let isFizz n = n % 3 = 0;; >let isBuzz n = n % 5 = 0;; >let isFizzBuzz n = isFizz n && isBuzz n;; >let FizzBuzz n = > match n with > | n when isFizzBuzz n -> "FizzBuzz" > | n when isFizz n -> "Fizz" > | n when isBuzz n -> "Buzz" > | _ -> n.ToString();; とするか、上記でもむしろまだ冗長で、潔く >let FizzBuzz n = > match n with > | n when n % 15 = 0 -> "FizzBuzz" > | n when n % 3 = 0 -> "Fizz" > | n when n % 5 = 0 -> "Buzz" > | _ -> n.ToString();; とでも書いた方が現実的ではある。 Fizz-Buzz 問題ごときにアクティブパターンを持ち出すと、C# が基本の今の自分にはかえってややこしくなる感じだ。 ややこしくても釣りがくるような場面で F# の良さを活かせたらいい、などと考えている(まぁ、自分が F# に不慣れなだけだとは思いつつ、実務への応用を考えるとチーム開発という事情も当然無視できないわけで)。 という能書きはさておき。 実際問題、上記後者の記述でもだいたいイケてるとは思うのだが、やはり、「3の倍数なら Fizz」という命題に対して、「3で割った余りがゼロならFizz」という記述になっており、その点もっとなんとかならないのか、という感じは確かにする。 そういうわけで、前回のパラメタライズドアクティブパターンを使った解法では、 「a が n の倍数なら true を返す、XisMultipleOf というアクティブパターン」 を定義したわけだが、ふと見返してみるに、 「これって、n が a の倍数なら true を返す二項演算子があれば、それですむ話では!?」 と思い至った。 すなわち、「n が a の倍数のときに true を返す n isMultipleOf a という二項演算子」を定義できれば、 >let FizzBuzz n = > match n with > | n when n isMultipleOf 15 -> "FizzBuzz" > | n when n isMultipleOf 3 -> "Fizz" > | n when n isMultipleOf 5 -> "Buzz" > | _ -> n.ToString();; と記述できるのではないか? こっちのほうがより直感的ではないか? と思い至ったのである。 パラメタライズドアクティブパターンによる解法の場合は、アクティブパターンの戻り値を含めたパターンマッチを記述せねばならなかった。 そのせいでせっかくのアクティブパターンによる直感的記法を大いに損なっていた感がある。 なのであれば、もうアクティブパターンにはこだわらずに、ただの C# の swith 相当でいいから「|n when n ...」のガード条件記述を使い、代わりに読みやすい二項演算子があれば十分、と考えたわけだ。 しかし。 結果は失敗。 さすがの F# といえども、ありとあらゆるシンボルを二項演算子としてユーザー定義できるわけではないそうである。 こちらの「新しい演算子の作成」の節を見ると、 http://msdn.microsoft.com/ja-jp/library/dd233204.aspx 「演算子文字として使用できる文字は、!、%、&、*、+、-、.、/、<、=、>、?、@、^、|、および ~ です。」 と明記されていた。 どうあがいても「n isMultipleOf a」と書けるような isMultipleOf 演算子は定義できないようだ。 ...と、ここで着目したのがパイプライン演算子("|>" と書く)。 パイプライン演算子を使うと、LINQ のメソッドチェインよろしく、左辺の結果を右辺の関数の引数に流し込んでくれるのだ。 まずは準備として、(演算子としては定義できないけれど、普通の関数として) isMultipleOf 関数を定義する。 >let isMultipleOf = fun divisor x -> x % divisor = 0;; 引数の順番が重要。 というのも、上記 isMultipleOf 関数は約数 divisor とテストする値 x の二つを引数にとって、x が divisor の倍数かどうかを bool で返すわけだが、ここで約数 divisor を指定して部分適用を行いたいのだ。 部分適用にて、引数 x ひとつだけを受け取る「x が **** の倍数か否か」を返す関数に仕立てることで、これをパイプライン演算子の右辺に持ち込むことができるようになる。 なので引数 divisor を第1引数に持ってくる。 すなわち、 >let isMultipleOfFive = isMultipleOf 5;; とすることで、「引数が5の倍数かどうかを返す "isMultipleOfFive" 関数」が定義できるわけであり、 >isMultipleOfFive 45;; は、パイプライン演算子を使うことで、 >45 |> isMutipleOfFive;; と書けるようになる。 isMultipleOfFive 関数 は元はといえば isMultipleOf 関数の部分適用に過ぎないので、これを元に戻すと、 >45 |> isMutipleOf 5;; となるのだ。 ということでゴールはこちら。 >let isMultipleOf = fun divisor x -> x % divisor = 0;; >let FizzBuzz n = > match n with > | n when n |> isMultipleOf 15 -> "FizzBuzz" > | n when n |> isMultipleOf 3 -> "Fizz" > | n when n |> isMultipleOf 5 -> "Buzz" > | _ -> n.ToString();; ...まぁ、最初の「演算子の自作」構想から比べると、結局 "|>" という "邪魔者" が混じってしまったせいで、これがモアベターとは言えない感じがしてきた。 とりあえずこんなところか。 ちなみに、Fizz-Buzz 解の実行は、 >List.map FizzBuzz [1..100];; とやっていたが、パイプライン演算子を使うと、 >[1..100] |> List.map FizzBuzz;; と書ける。 こっちのほうが LINQ 大好きな C# ユーザーとしては、LINQ を彷彿とさせるので好みだ。 Enumearble.Range(1,100).Select(n => FizzBuzz n); みたいでしょう? 対応表: Enumearble.Range(1,100) ---> [1..100] Select ---> List.map ということで。 C# の LINQ でドットでつなぐところを、F# では |> でつないでいけるわけだ。 2010/05/07 追記 上記対応表は、厳密に言うと正しくない。「対応するコードの部位」という意味では合っているが...。 まず、F# の [n..m] が返すのは List であり、C# の Enumerable.Range が返す IEnumerable 強いて言えば、Enumerable.Range(1,100).ToList() とでもすればより合致するかと。 また、C# の IEnumerable いずれも "射影" という点では同じだが、List.map は List しか処理できなかったり、Seq.map はその仕組み上遅延評価だったりする。 ...といったことを、igeta さんにご教示頂きました。多謝。
by developer-adjust
| 2010-05-06 23:21
| .NET
|
ファン申請 |
||