【Haskell】バインド演算子(>>=) の解釈
プログラミングHaskellの8章を読んでいて,Haskellのバインド演算子>>=について1週間ほど悩んだのでメモ。
まずghciでバインド演算子の型を聞くと,
ghci> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b
と返ってきます.悩んだのは,第二引数の a-> m bの解釈でした.
型をそのまま読むと,「a型の値を受け取って,b型のmを返す関数」という意味になりますよね.
本の8章には,モナドのインスタンスとしてパーサーが取り上げられていたのですが,a型の値を受け取ってるのにb型のパーサーを返すの?こんな関数あるの?と実体が想像できず理解に苦しみました.
まず本に掲載されていたパーサーの型を再確認すると,
type Parser a = String -> [(a, String)]
です.つまり「解析したい文字列 を受け取って, [(解析結果 :: a , 残り)] という組のリストを返す」という型です.
なので,バインド演算子の第2引数に来る関数は,
「第一引数のパーサーでの解析結果をなんやかんやして,また新たなパーサーを作るよ」
みたいな解釈が良いなと思いました.
「なんやかんや」の部分は,例えばそのまま捨てるでもいいし,例えばそのまま返すでもいいし,例えば次のパーサーで使う判定条件に組み込んでもいいし...といった具合だと解釈してます.
【久々】ブログも見事に一瞬で飽きた件【適当】
こんばんは。
「飽き性の生きる道」と題してブログを始めてみたはいいものの、みごと一瞬で飽き、1年半ほど触れていませんでした。
再開することにしました。
理由は「誰かに僕を発見してほしい」という気持ちが強くなったからです。
あと、最近、大学の部活を辞めて少し暇になったのです。辞める時に考えていたことや精神状況について、なにか書こうかなと思ってます。
無理のないペースで続けていきます。
よろしくお願いします。
【根本的な話】おれのやりたいことってなに?【随想】
こんにちは,今日は「自分のやりたいこと」をなんとかして見つけていきたいな~という記事です.
自分は何になりたいのか,何になりたくないのか.そういったものは憧れからくるのかもしれませんね.
最近やりたいことは,
だけどどの欲望もその根源が自己顕示欲とか性欲とかなのかもしれないって考えると,自分ってしょーもない人間なのかなぁってなりますね.
結局ラクしたいってのが全ての根源なのかもしれないとも思えてきました...
なんだかよくわからんのでこのくらいにしておきます.
OCamlから離散数学の香りを感じる(初歩的)
こんにちは,matsuwakaです.最近
いまSICPを読むのは時間の無駄 - きしだのHatenaというブログを読んで,SICPも読みつつ,浅井健一氏の「プログラミングの基礎」という本でOCaml(オーキャムル)の勉強をしているんですが,OCamlになかなか(離散)数学味を感じたので少し書こうと思います.とはいえ数学的に近い記述ができるのがOCamlの特徴なのであたりまえではありますが.
OCamlから見える写像と集合の表現
例えば関数f(x) = x^2を定義しようとします.OCamlでは極めて直感的に定義出来て,
# let f(x) = x*x;;
となり,これをインタプリタに打ち込めば
val f : int -> int = <fun>
というのが出力されます.これは「int型からint型への写像ですよ」ということを意味しています.これはそのまんま数学の写像の書き方と同じですよね.(定義域はRではないけれど)
また,こういうのを応用すれば,
# let f(x,y) = x*x + x*y + y*y;;
ということもできて,これをまたインタプリタに打ち込めば
val f : int * int -> int = <fun>
というのが出力されます.この時注目してほしいのは,int*intという部分です.カンの良い人ならもうお気づきでしょう.そうです,集合の直積を表しています.(数学で書くなら,int*intはZ×Zになりますが.)
どうでしょう,ほとんどそのまま数学の記述ができますね(スバラシイ).ぜひOCamlいじってみてください.
それでは,失礼致します.
SICPまとめ① ~アッカーマン関数~
こんにちは.
最近SICP(読み方:シクピー)をやり始めました.SICPっていうのは,「計算機プログラムの構造と解釈」っていうマサチューセッツ工科大学の教科書です.
700ページくらいあるのでさすがに購入するのは躊躇してしまい,ウェブにあがってるpdf版を見ながらやってます.タダより高いものは無いの精神で行きましょう.
それで今日からちょっとずつSICPについてまとめようかなと思った次第です.まとめつつ読みつつだと何年かかるのやらって感じなんですけど,ゆっくりやって飽きたらやめます.
さて,今日は1.2.1のアッカーマン関数について書きます.
目次は以下です.
アッカーマン関数の定義
そもそもなんでアッカーマン関数が出てきたのかというと,SICPの1.2.1というのは再帰が主題になっていて,アッカーマン関数もまた有名な再帰的な関数だからなんです.
A(x, y)について
- y = 0ならA(x,y) = 0
- x = 0ならA(x,y) = 2*y
- y = 1ならA(x,y)= 2
- それ以外は,A(x, y) = A(x-1, (A(x, y-1)))
.....ちょっとよく分かりませんね.ただ4つ目の式にアッカーマン関数Aが呼び出されていて,再帰的な構造であることが確認できます.ただイマイチどういう役目かわからないので,具体例を見ていきましょう.
具体例で見るアッカーマン関数
まずはA(1, 5)についてみていきます.
さて,上から1行ずつ見てほしいのですが,xが1, yが5なので4つ目の条件に該当します.
- それ以外は,A(x, y) = A(x-1, (A(x, y-1)))
というやつです.アッカーマン関数の第二引数にアッカーマン関数があるので,こいつが値を返すまで呼び出され続けるわけですが,この場合だとA(1,1)で呼び出しが一旦終わって,赤字の評価に入っていきます.
A(1,5)においては,一番初め以外第一引数が0なので,
- x = 0ならA(x,y) = 2*y
という条件に引っかかってくれて,常にyの2倍を返していきます.なので任意の自然数nについてA(1,n)は2^nを表していることになります.
つづいて,A(2,3)についてみてみましょう.
こんな感じです.(h 3)っていうのは無視してもらって構いません.3行目を見てください.(A 1 (A 2 2))っていうことは,先ほどのA(1,n)を用いれば,2^(A 2 2)で表せることに気づきます.
でもって今求めてるのは(A 2 3)...
一般化できそうな匂いがしますね.要するに,(A 2 n) = 2^(A 2 (n-1))ってことです.
ただこれって,右辺をほどいていったら2^2^2^2^2^.....ってことじゃないですか.
計算量えぐいですよね.
実際上の写真でもとめた(A 2 3)=16をつかうと,(A 2 4)=2^16
=65536で,これを使って(A 2 5)をもとめようとすると.....
2^65536=200352993040684646497907235156025575044782547556975141926501697371089405955631145308950613088093334810103823434290726318182294938211881266886950636476154702916504187191635158796634721944293092798208430910485599057015931895963952486337236720300291696959215610876494888925409080591145703767520850020667156370236612635974714480711177481588091413574272096719015183628256061809145885269982614142503012339110827360384376787644904320596037912449090570756031403507616256247603186.....
あほかー!
アッカーマン関数を一般化する
気を取り直して最終的な一般化をしていきます.
SICPでは,
2*2*2*....(nこある)=2^n
2^2^2...(nこある)=2^^n
2^^2^^2^^...(nこある)=2^^^2という風に定義するんですね.(なかなか秀逸な定義)
こうするとアッカーマン関数の第一引数における一般化ができて,結局アッカーマンA(x,y)っていうのは
2^^^^^...^^^^(xこある) yってことになるわけです.(しんどい)
こうやってまとめてみると意外と俺理解できてるやんってなって楽しいですね.今日はこのへんにしておきます.
それでは,失礼致します.
【根本的な話】"考える"ってなんやねん-2 ~良質な問とは~
大学のレポート課題に飽きた(もともとやる気が無い)のでブログを書くことでとりあえず頭を動かしておこうという目論見です.
前回のブログで「考えることは問いを出して答えること」っていう話を書いたんですが,今回はその続きで,「じゃあ良質な問ってどないして出すねん」っていう問いに対して答えていきたいと思います.(これも”考える”作業である!)
目次はこんな感じです.
それではよろしくお願いします.
デカルトの「方法序説」から見えてくる学問の基礎
まずデカルトって誰やねんって人はめちゃめちゃ賢いひとだと思っておいてください.
第二は,わたしが検討する難問の一つ一つを,できるだけ多くの,しかも問題をよりよく解くために必要なだけの小部分に分割すること.
要するに「考えたい大きい問いは,分割せえよ」ってことです.
これは分析の規則とよばれる規則で,デカルトはこのほかにも3つの規則を挙げていて,学問の根本的方法は分析の規則を含めた4つで事足りるということを「方法序説」で述べています.
これを踏まえてどういう手順を踏めばいいかってことを以下に示していこうと思います.
step1.大まかな問を出す
(相変わらず私の主観で書いてるので鵜呑みにはしないでください.)
それじゃあ説明していきます.大まかな問を出すってことなんですけど,これは目標を立てる時にもよくやるんちゃうかなーと思うんですが,まずは何でもいいので自分の中で違和感があること,理想像,改善したいことなどを挙げてみます.これは本当に何でもいいと思ってます.(プログラミングがうまくなるには?とか,英語が話せるようになるには?という問から,なぜ世界から差別は消えないのか?といった問でもなんでも)
この記事では例えば「この記事をどうまとめるか?」という問について考えていってみましょう.
~ここまでの進捗~
問:「この記事をどうまとめるか」を生み出した.
step2.問の分解
最初に注意があって,問いを立てるのは自由だと思いますが,問いの分解は自由ではないです.先ほどの分析の規則のところを見てもらいたいんですが,デカルトはあくまで,”問題をよりよく解くために必要なだけの小部分に分割すること”って言ってるんです.何でもかんでも片っ端から分割していってもいいとは言ってないんですね.
だから例えば,今あげている問「この記事をどうまとめるか.」について,以下のような問いは良くないってことです.
- ”この”という言葉はどういう歴史で使われてきたのか?
- なぜブログの投稿のことを"記事"と呼ぶのか?
- 最後の"か”というひらがなは疑問詞?
etc...
こういった問は本題を解決することに役に立たないと”直感的に”分かると思います.(「直感的にかよ...」という反論への対策として,そのうち論理はバカのために存在するという記事も書きますのでご安心を.)
じゃあどうすれ必要なだけの小部分に分割できるのかという話になりますが,僕が意識していることはシンプルで,定義に立ち返ることです.問の題意が分かっていないまま考えようとするから思考がぼんやりするんです.こういうことを回避するために,問に現れる言葉の定義に立ち返ったときに生まれてくる疑問を新たな問にすることが大事だと思います.
では,私の問「この記事をどうまとめるか」について細分化してみましょう.この場合,定義としてなんだか曖昧そうなところを抽出すれば,
- 「まとめるってなんやねん?」
という問いがさらに生まれてきます.今回は大きい問いではありませんから,細分化といっても本質はここくらいなので,分割後の問いは一つで十分でした.
~ここまでの進捗~
問:「この記事をどうまとめるか」→「まとめるってなんやねん?」と,問いを細分化した
step3. step2への回答とさらなる細分化を繰り返し,主題への解を作り上げる
結局はこのサイクルを繰り返していって,最終的に主題への解に到達できればいいわけですね.では例に移りましょう.
問:「記事をどうまとめるか?」→「まとめるってなんやねん?」
- 問-1「まとめること」=頭の中にある案をシンプルにすることと仮定してみよう.↓
- 問1-1.目次は全部で何項目にする? → 問1-1-1.書きたいことは何個ある? →解1-1-1.stepで3個,はじめとおわりで2個ぐらいにしよう↓
- 解1-1.目次は5個にしよう
- 問1-2.内容は何かく? → ........
っていうのを繰り返して戻っていって...という具合になると思います.書いてるとこんがらがってきますので次項にまとめます.
まとめ
- 問いを出す
- 分解した新たな問を生み出す
- 答える&2を繰り返す
っていう順番ですね.またなにかあれば編集,追記していくと思います.
レポートがやっと終わって嬉しかったマンです.
それでは,失礼致します.
【根本的な話】"考える"ってなんやねん
こんにちは,matsuwakaです.1分前に自己紹介の記事をアップロードしたんですけど,モチベがややあるのでもう一つ記事を書いてみようと思います.
目次はこんなもんです.
"考える"とは問を立ててそれに答える作業を繰り返すことである.
いきなり答えを書いてしまいましたが,そうなんです.考えることって,問いに対して答えていく作業なんですよね.
これは私が通っている旧帝大の解析学のI先生が常々おっしゃっていたことなんですけど,ある人が”考える”っていうワードを聞いて,「頭に浮かんだなんだかよくわからんモノをこねくり回すこと」だと思うことって多いと思うんです.だって辞書の1番目の意味にも
かんが-える
1.あれやこれやと思いをめぐらす。その事について、心を知的に使って判断する。
って書いてますし.(”考える 意味” でググってください.)実際私もそういうもんだと思ってたんですよ,大学に入るまでは.
例えば数学の試験では,「えーっと,これ分かんないから考えるか(ぼけーーー)」っていうことは500万回ぐらいやってましたし,予備校の授業でも「んん?何言ってんのこの先生,ちょっと考えよ(ぼけぼけーーー)」っていうことが720万回くらいありました.
でも本当はそういうことじゃないんですね.詳しくは以下です.
問に答えることはなぜ考えることなのか?
(ここからは私の見解ですので,鵜呑みにしないでください)
問いに答えることって,要は創造することだと思うんですよ.何かを作り出すことだと思うんです.
で,私は「考えるという行為は解決,創造のためにある」と勝手に思ってますので,じゃあ問いに答えることは考えることなんだなあ...と結論付けました.
ちょっと自分でも何言ってんのか分からなくなってきたので,図解してみました.
双方向矢印は対比じゃなくて同値です.(⓪の矢)
何かを創造するためには必ず考えることが必要で(①の矢),問いに答えているならば必ず何かを創造してる(なぜなら,解を生み出してるから)(②の矢)ってことですね.②が真かつ①が真なので,「問いに答えてるなら考えてるでしょ」ってことが言えました.
次回予告
じゃあ具体的にどういう問いを立てればいいの?って話になってくるんですけど,それはまた今度書こうかなと思います.
結論だけ言っておけば,「小さな問から始めていけ」というのが答えです.
次回はデカルトの「方法序説」を踏まえてこれについて考えたいと思います.
なんだかこうやって書いてみると意外と思考浅いなぁってなりますね.精進します.
それでは,失礼致します.