FParsecのチュートリアルでJSONParserをVisualStudio2015で実行する方法

Haskellのパーサーライブラリーparsecは、いろんな言語に移植されていてF#でもFParsecがあります。今回はVisual Studio 2015で、FParsec 日本語チュートリアル – a wandering wolf を試してみました。

使ってみた感想

まさか自分でJSONパーサーを作って動かすことができるような日がくるとは思ってもみなかったのでとてもうれしいです。関数型プログラミングを勉強すると再帰をたくさん使うので、以前よりBNFの再帰構造にも抵抗なく取り組めました。まだ使い慣れていないので、難しい問題に取り組むよりかは、iniファイルなどを自分で実装してみたいです。

FParsec,FParsecCSをロードする方法

F#でfsファイルを使うときにF# InteractiveにDLLライブラリーをロードさせる方法 手動で、FParsec,FParsecCSをロードする方法を上記に書いています。

参照設定を手軽にfsxファイルに取り込む方法

ソリューションエクスプローラの[参照設定]を右クリックすると[Generate References for F# Interactive]がコンテキストメニューに表示されるのでそれを右クリックスト、Scriptsフォルダーが作成され、load-project-debug.fsx、load-references-debug.fsxが作成されます。load-project-debug.fsxの中で、load-references-debug.fsxを読んでいます。私たちがfsxで読み込むのは、load-project-debug.fsxになります。

この例のように、CSVParserプロジェクトで、HelloParser.fsxなどを新規作成する場合、fsxファイルに、以下のような#load文を書けばロードできるようになります。注意点としては、Scripts/のようにScriptsフォルダーを指定しないといけない事です。

参照設定は、NuGetでライブラリーを取得したり、既存のライブラリーを参照に追加した場合のみへんこうされます。なので面倒ですがそのたびにこの手順を踏む必要がありそうです。

load-references-debug.fsxの書き換え

[Generate References for F# Interactive]で、load-references-debug.fsxを生成した時は、以下のように、FPharsec.dll、FParsecCS.dllという順番になっています。

FPasrsecのDLLは、FParsecCS.dll、FParsec.dllの順番でF# Interactiveに読み込ませる必要があるので、コピーペーストで、FParsecCS.dllとFParsec.dllの順番を入れ替えます。

これで、Ctrl+Aでファイルを全選択して、Alt+Enterで、F# Interactiveにファイルを流し込めます。

文法の単純な見落としに注意

以下が正しいソースコードですが、

以下のように書いて、コンパイルエラーが取れずに頭を抱えてしまいました。

F#では、リストの区切り文字は、セミコロンで[要素1;要素2;要素3]のように記述します。また、複数行にした場合は、セミコロンを省略できます。よって、以下2つは同じです。

普段、Ctrl+K,Ctrl+Dで整形をしますが、以下のような書き方だと、当たり前ですがフォーマッターは、要素1の引数と判断してしまい、整形することはできません。

jobjectの書き方やFPharsecのライブラリーのロードに問題があると思いずっとそちらを調べていたのですが、実際は単純な文法エラーでした。

 

チュートリアルを試した感想としては、もし問題が発生した場合はソースコードをソースコードの入手方法

FParsec Documentation – 3 Download and installation の3.2の部分に以下の引用がありソースコードがFParsecのzipファイルがありその中のSamples/JSONに今回のサンプルのソースコードがあります。

You can “clone” the source code using Mercurial (HG) or you can download it as a zip‐file.

 

ソースコード

最後の行に、runParserOnFileで、実行する行を追加しています。

FSharpでmatch式をつかった直積の書き方

JavaやC#の場合、二重のfor文を実行すれば、x,yの直積が完成します。F#でもリストの内包表記で、二重のforにより直積が作れます。関係代数について調べていた時に、stackoverflowにmatch式を使った直積の書き方を見つけました。

関係代数やリレーショナルデータベースは、集合と関係してくるので、数学の集合論や関数型プログラミングで写像とかで学んだ知識がそのまま使えるのはうれしいです。

http://www.cs.reitaku-u.ac.jp/infosci/rdb/rdb02.html

関係代数

関数型プログラミング言語F#初心者向けURL集

関数型プログラミング言語F#を学んでいくうちにいろんなサイトを見つけたので整理すると同時に公開して情報共有します。

関数型の考え方が分かるサイト

F# for fun and profit は英語のサイトなので大変ですが、Learning  F# で関数型で考える心得や、やっていいこと悪いことなどを説明しています。また、Thinking functionally は他の入門サイトと異なり、集合、写像、関数の簡単な説明から始まります。英語ですが関数型プログラミング言語でこの土台が分かるとHaskellやStandardMLなどの基礎部分は同じものとして理解することができます。英語を読むのは本当に大変ですが、このサイトはお勧めです。

文法を学習するために便利なサイト

普通リファレンスは厳密で難しい場合が多いですが、マイクロソフト公式のF# 言語リファレンス は、説明とともに、すぐ動かせる小さなサンプルが豊富にあります。なので、適当な入門サイトでおおよその文法を学んだあとは、このリファレンスを観るのが効率が良いです。

かずきのBlog@hatena さんのサイトで、以下のURLに、F#の文法の記事が25個ぐらいあります。

 

 

興味深い資料

プログラミングで同値関係が分かる!

数学の「関係と集合」まで進んだら、同値関係(Equivalence relation)の説明で、反射律、対称律、推移律、反対称律が出てきました。教科書の言い回しは難しくて何言っているのか分からなかったのですが、プログラミングで考えれば簡単なことでした。関係演算子の機能チェックをするルールを律と言っているだけでした。

プログラミングで使う演算子のおさらい

私たちは普段何気なく使っていますが、演算子はいくつかグループに分けられます。それでイコール記号や大なり小なりは関係演算子と言います。

算術演算子 + - * / %など

関係演算子 == != < <= > >=

論理演算子 && || !

関数型言語の演算子を見てみる

F#のような関数型プログラミング言語では、算術演算子、関係演算子、論理演算子は、どれも関数として使えます。1 + 1のような加算演算子は、中置記法で使いますが、()を使うと前置記法にできます。この前置記法は、プログラミングで私たちが良く作る関数と同じ順番です。関数名、第一引数、第二引数となっています。

JavaScriptの場合は、add関数を作ってx + yをその中に書けば、算術演算子+を別名のadd関数として作れます。

関数型言語の場合は、先ほどの前置記法があるので、add関数で包むという感じではなく、別名を用意する感じです。以下のようになります。

 

ここでひとつ分かることがあります。私たちはプログラミングで演算子を使っていますが、関数で演算子を包んであげれば、関数として使えて、add(x,y)のように、名前を前に持って来ることができます。

等号の関数を作ってみる

JavaScriptの場合は、==で、値が同じかどうかを比較するので、この演算子をeq関数で包めば等号の関数が作れます。

F#の場合は、=が値が同じかどうかを比較します。かなり省略した表記なので、なれないと見づらいです。

ここまでで、add関数、eq関数を作ってみました。これらは+演算子や=演算子と同じように使えます。

K演算子を作ってみる

謎のK演算子を作ってみます。といっても、以下のようにプログラミング言語に演算子Kを追加することはできません。

ですが、add関数やeq関数と同様に、K関数を作って演算子に見立てることはできます。K演算子の中身はなんでもいいのですが、「3で割ったときのあまりが等しい」という演算子にしてみます。

JavaScriptだと以下のような感じです。

F#だと

K関数(K演算子)を作ってみました。ここで問題ですが、K関数(K演算子)は、どのような機能を持っているのでしょうか、=演算子と同じ機能を持っているのでしょうか、それとも>演算子と同じ機能でしょうか、>=と同じ機能でしょうか。

この性質チェックをするのが、数学でいう、反射律、対称律、推移律、反対称律です。何々律というのは実際にはもっとたくさんありますが、教科書では必要な部分しか説明していません。

それで、反射律、対称律、推移律の3つをパスできれば、同値関係つまり、プログラミングの==記号と同じですという事ができます。もしK関数(K演算子)が、同値関係なら、==演算子としても使えるという事になります。

また順序関係もあり、こちらは、反射律、推移律、反対称律、全順序律を満たす必要があります。もしK関数(K演算子)が、順序関係なら、大小の比較にも使えるという事になります。

書きかけのソースコード

正しくない部分があると思いますが、ひとまず雰囲気だけでも分かると思いますので、書きかけのソースコードも載せておきます。

 

 まとめ

数学の問題を解くのではなく、どうにかしてプログラミングの問題にしてしまえば続けられるのが分かってきました。

参考資料

 

F#ではfold_left、fold_rightではなくList.fold、List.foldBack?

F#入門 fsharpintro.netのfoldの記事を見ると、Let.fold_leftとList.fold_rightになっていますが、マイクロソフトのAPIリファレンスを見るとList.foldとList.foldBackになっています。調べてみると機能は同じですが関数型言語によっていろいろ呼び方が違うようです。foldについては中身を実装していないので、もう一度ちゃんと勉強してみます。

手始めに、map関数などを書いてみる

OcamlとF#は、map関数などの実装方法がたくさんサンプルとしてあるので、何回も繰り返し書くことで学習できます。sum関数、map関数、reverse関数が簡単なのでまずはこれらから覚えるのがよさそうです。

https://en.wikibooks.org/wiki/F_Sharp_Programming/Lists

map関数

map関数は、List.mapがあっても気づいたときに何回も書いていたので、すぐ書けるようになりました。

リバース関数

 

fold関数、foldl

実装が難しそうと想像していたのですが、実際に書いて頭の中でステップ実行してみると全然難しくありませんでした。人が書いた記事を読むのでなく、自分で書いて、自分の頭の中でステップ実行するとよいようです。

ソースコードを書いて、上記のコメントのように書きながら1行ずつ脳内実行してみるとmap関数やreverse関数の知識で問題なく理解できます。

foldBack関数、foldr

https://en.wikibooks.org/wiki/F_Sharp_Programming/Lists を参考にして自分の分かりやすい変数名で書いてみて、コメントで書きながら脳内実行。

ひとまず、じぶんで実装して処理を追えるようになったのでいい感じです。次は使い分けを調べてみようと思います。

http://stackoverflow.com/questions/9055837/difference-between-fold-and-reduce

 

F#で末尾再帰

関数型プログラミング言語ではfor文などでループをしない代わりに、関数内で自分をさらに呼び出す再帰呼び出し(recursive call リカーシブ・コール)をします。例えば以下のように合計を求めるsum関数では、関数の中にsum (n-1)のように自分自身を呼び出します。関数を呼び出すと、戻り値で戻ってくる場所と引数を保持するためにスタックが用意されます。関数が繰り返し呼ばれるとスタックがどんどん増えていくので、数万回呼び出すとStackoverflowが発生します。

普通の再帰関数

F# Interactiveでsum関数を呼び出すと、以下のようにStackOverflow例外が発生します。これは書いたプログラムに問題があるので、例外処理(try)で補足することはできません。

これを回避するには、末尾再帰(tail call)を行います。

末尾再帰(tail call)

これをやると、アセンブラではcallではなく、jumpになるので、命令型プログラミング言語のfor文と同じで、どんどんスタックを消費するという事がなくなります。

書き方のコツは、あまり難しく考えずに、また下手に難しい問題を書こうとせずに、思い出したときにsum関数と末尾再帰版のsum関数を書いてみるとよいです。私はすぐ忘れるので、気づいたときに何回も書いていたら書けるようになりました。

 

 

 

艦隊これくしょんの艦娘をソートできるWebアプリを作ってみる

せっかくF#でWebスクレイピングをしてCSVデータを作成したので、それをSQLiteにデータ登録して、ロリポップで表示してみました。とりあえず、SQLiteなのでマルチカラムソートに対応してみようと思います。

艦隊これくしょん おてがる艦娘ソート(開発中)

001
表示できた!

 

FSharpでWebスクレイピング

wikia.comの艦これのデータを取得してみました。昨日のソースコードだとCSVに形式にできましたが、カラムのずれがありました。wikia.comのHTMLでは日本語名と英語名を分けて書かずに改行を使って書いていたり、イギリス艦はカタカナ表記がないので、泥臭く調整する必要があります。

001

 

SQLite3に取り込んでみる。

CSVファイルが正しいかどうかはデータベースで取り込んでみるのが手っ取り早いのでsqlite3にインポートしてみます。

sqlite3のコンソールを初めて使ったのですが入門情報が豊富なので問題ありませんでした。sqlite3のzipを回答したらsqlite3.exeがあるので、powershellから適当なファイル名(kancolle.db)でデータベースのコンソールに入ります。あとはデフォルトの区切り文字が(|)なので、.separator , でカンマに変更して、つくったcsvファイルを流し込みます。

002
DBBrowser for SQLiteで確認できた!

まとめ

インターネットのHTMLファイルから、データを取得してCSVファイルを作成し、データベースに格納するところまでできました。wikiなどのデータは手入力も多いため規則性がない場合は泥臭いところをしなければいけない場合も多いです。

関数型言語を道具として使う

今回は、PythonやBashで出来ることをF#でやってみました。文法を勉強しているときは全く感じなかったのですが、実際に実用的なアプリを作ってみると、C#の.NETのコードをそのままぶち込めたりして、思った以上にUnityやC#で学んだ知識をそのまま使っていけるのが分かりました。逆に.NETのAPIで、F#のインタフェースを用意していないのに驚きました。

F# Interactiveを使う開発は、Bash/Sed/Awkなどでやる泥臭いテキスト作業やコンソールでの開発と同じスタイルで、C#やJavaと同等の開発スタイルを想像していたのでこれも大きな発見でした。

次回はせっかくなので、作ったCSVまたはSqliteのデータをPHPかJavaでインターネット上に公開しようと思います。

 

F#でfsファイルを使うときにF# InteractiveにDLLライブラリーをロードさせる方法

参照設定しているライブラリーをF# Interactiveにロードする方法

ソリューションエクスプローラーからプロジェクトを展開して、その中の[参照設定]でコンテキストメニューを右クリックで表示して、[参照をF# Interactiveに送信]で可能です。

a03
参照設定のライブラリーすべてをロード

FParsecライブラリーは、FParsecCS、FParsecの順番にロードする必要があります。このような場合は、ライブラリーを一つずつ選択して[F# Interactiveに送信]で可能です。

a04
ライブラリーを個別にロード

F#の実行形式

F#は、fsxファイルというスクリプト形式と、fsファイルというC#やJavaなどのコンパイル形式があります。fsファイルの場合はC#と同じように、プロジェクトに参照設定を追加して、緑の▶実行ボタンを押したら、参照設定のライブラリーを読み込みます。

ただし、F# Interactiveは、fsi.exeをVisual Studio Community 2015で呼び出しているだけのためプロジェクトの参照設定を自動でロードしてくれたりしません。なので、以下のソースコードのように他のライブラリー(ここではFParsec)をNuGetで参照に追加した場合、Visual Studioの緑の▶実行ボタンではどうするけれど、F# Interactiveではエラーが出てしまいます。

上記をエディター上でCtrl+Aで全選択して、Alt+Enterで、F#Interactiveに流し込むと以下のエラーが出てしまいます。

一番最初に紹介した[参照をF# Interactiveに送信]以外にも、[ツール]->[オプション]でオプションダイアログを表示して、F# Interactive オプションで、-rオプションによる指定も可能のようです。

001

 

もっと楽にfsxファイルでライブラリー管理をしたい

今回[参照をF# Interactiveに送信]を見つけたのですが、それ以外にもコンテキストメニューに[Generate References for F# Interactive]を見つけました。これを実行すると、Scriptsフォルダーに自動生成してくれるので要調査です。

 

関数型言語F#のラムダ計算で引き算ができません

はじめに

関数型プログラミング言語は、ラムダ計算という仕組みが元になっているというのをよく入門記事で見かけます。実際にラムダ計算を調べてみると基本ルールはとても小さく、関数だけで数字や演算子を作り上げる面白い仕組みというのが分かりました。

また、F#やHaskellは文法上、括弧が少なくカリー化で引数がひとつずつ繋がっているのでラムダ計算の表記をF#にとても落とし込みやすかったです。たぶんHaskellも同じようにやりやすいのだと思います。私のスキルはFizzBuzzを書くぐらいのレベルですが、興味のある事をしないと命令型言語に戻ってしまうのでF#でラムダ計算をやるだけやってみました。

問題点

以下ソースコードは、https://en.wikipedia.org/wiki/Church_encoding を参考に書きました。コードの次に書いてあるエラーのように、型が一致しませんの表記がすごいことになっていて、とても解決できるものではありません。

ソースコード

 

 

型が一致しませんエラーが解決できません。

66行目、let test021() = minus n2 n2のコメントアウトを外すと型が一致しません。というエラーが発生します。

 

いろいろ調べてみる

“F# lambda calculus”などで検索すると、”A Lambda Calculus AST”などが見つかるので、こういうソースを追いかけてみるもの良いのかもしれません。pureというプログラミング言語だと近い表記で実装できそう。

Haskellでもエラーがでる?

  • http://d.hatena.ne.jp/mokehehe/20080202/lambda
  • http://d.hatena.ne.jp/katona/20100615/p1
  • http://d.hatena.ne.jp/katona/20100427/p1
  • https://uid0130.blogspot.jp/2013/05/x.html