Haskell で順列のプログラムを作ってみた

Haskell でリストの要素を使った順列を列挙する関数をプログラムしてみた。このような関数を perm とすると、関数型は perm :: [a] -> [[a]] となる。

そこで先ず perm [] の値を考えてみる。これは [[a]] 型になり、[] の順列は [] 一個だけだから perm [] = [[]] になるはずだ。そこで prem [] と同じ動作をする関数を次のように perm0 x として定義する。

Prelude> let perm0 [] = [[]]
Prelude> perm0 []
[[]]

次に要素が1個だけの配列 [a] について perm [a] がどのように振る舞うかを考えてみた。これを perm1 として考えるが、あとで perm を再帰的に定義したいので、perm0 x との関係で考えてみた。

[a] の要素 a を取り出すと、[] が残る。perm0 [] = [[]] であることを考えると。a を使った順列は 、

map (a:) [[]]

になる。これは a と a を取り去った配列の全ての順列との結合を意味する。[a] から a を取り去ってできる配列は [] 一つだけだから [] の全ての要素の配列を集めたリストは [[]] だからだ。上の結果は ghci でも確認できる。

Prelude> map (1:) [[]]
[[1]]

さて、[a] から a を取り去ってできるリストはどうやって作ればいいのだろうか。それは filter 関数を利用すれば簡単にできる。

Prelude> filter (/=1) [1]
[]

部品がそろったので perm [a] と同じ動作をする prem1 [a] をプログラムすることができる。

Prelude> let perm1 x = map (\y -> map (y:) (perm0 (filter (/=y) x))) x
Prelude> perm1 [1]
[[[1]]]

この map が入れ子になっているプログラムがどんな動作をしているのかを説明するのは少しむずかしいが順を追って考えてみよう。

先ず最外側の map はリスト [a] から要素 a を取り出す操作を表している。これは、ラムダ関数の変数 y に引き渡される。内側の map はリスト (perm0 (filter (/=y) x) の要素を一つ取り出して y をその先頭に結合する。perm0 はどんなリストかというと、リスト filter (/=y) x の要素の順列からできるリストだ。さらに filter (/=y) x はリスト x から要素 y を取り去ってできるリストである。

具体的に [1] について上のプログラムがどう動作するかを考える。まず y には 1 が入る。もちろん x = [1] である。そうすると filter (/=y) x = [] である。従って perm0 (filter (/=y) x) = [[]] である。すると map (y:) (perm 0 (filter (/=y) x))) x = map (1:) [[]] = [[1]] だ。しかし、最外層の map もあるので結局 perm1 [1] = [[[1]]] になる。

perm1 [1] は上のプログラムでうまく動作するような気がするが、perm の型を考えると perm1 [1] = [[1]] となって欲しい。そこで perm1 の定義を次のように変更する。

Prelude> let perm1 x = concat (map (\y -> map (y:) (perm0 (filter (/=y) x))) x)
Prelude> perm1 [1]
[[1]]

perm1 [1] が動いたので perm2 [1,2] を考えてみる。perm1 x の定義は perm0 x との関係で定義していたので、perm2 x は perm1 との関係で定義できるのではないかと考えてみる。すなわち、perm1 の定義の perm1 を perm2 に perm0 を perm1 に変えてみる。驚いたことにこの企みは次のように成功する。

Prelude> let perm2 x = concat (map (\y -> map (y:) (perm1 (filter (/=y) x))) x)
Prelude> perm2 [1,2]
[[1,2],[2,1]]

調子に乗って perm3 [1,2,3] も試してみる。

Prelude> let perm3 x = concat (map (\y -> map (y:) (perm2 (filter (/=y) x))) x)
Prelude> perm3 [1,2,3]
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

再帰的定義の利点は、base case から初めて統一的な方法で recursive case のプログラムを記述できることだ。ここまで来たら目的の perm :: [a] -> [[a]] のプログラムをすることができる。これまでの perm0, perm1, perm2 を同じ perm で定義すればいいのだ。

Prelude> :{
Prelude| let
Prelude| perm [] = [[]]
Prelude| perm x = concat (map (\y -> map (y:) (perm (filter (/=y) x))) x)
Prelude| :}
Prelude> perm [1,2,3]
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

再帰的プログラムを考えるのは再帰的定義の部分のテストができないので難しくなりがちだが、base case から逆算的にテスト用の関数を作っていくと、テスト用の関数から再帰的定義に移行するのは意外に簡単だった。


[PR]
# by tnomura9 | 2017-03-14 23:15 | Haskell 記事リスト | Comments(0)

免疫学の知識

免疫学の知識は複雑な上に日進月歩なのでネットで調べても何が本当かわからない。信頼できそうな記事を見つけたのでメモ。


免疫学はたくさんの受容体やタンパク質が出てきて混乱するが、Tリンパ球の働きを中心に整理していくと少し分かりやすくなるのではないかという気がする。そのポイントとしては MHC-I と MHC-II の違いを理解するのがよいと考えた。

そこで MHC-I と MHC-II についてGoogle検索して、手当たり次第に文書や動画を閲覧したが、困った状況が発生した。確かに、インターネットのおかげで一般人も最先端の情報に触れやすくなってきた。しかし、一方ではネットの記事にはいろいろな解説があふれていて、ともすれば内容が全く異なっている。このため、どの記事が正しいのか分からなくなってしまったのだ。また、最先端の記事というのは後には否定されるような内容も含まれているはずだ。

学校の勉強と違って、実社会にはこれが正解といえるものはない。相反するような記述があったとしても動揺しない心構えが大切だ。このような混乱が嫌だからと言って、評価のほぼ確定した教科書だけを読むこともできるが、それだけでは面白くない。教科書は幹線道路だとしても、脇道の探索は結構楽しい。混沌とした知識というのは、今まさに成長しつつある知識、生き生きと変化している知識だからだ。

内容が混とんとしている知識を得る価値を測る物差しとしては、学んで楽しいかどうかを基準にするといいのかもしれない。

[PR]
# by tnomura9 | 2017-03-12 22:20 | 考えるということ | Comments(0)

対比させない

Tリンパ球のヘルパー細胞には Th1 と Th2 の2種類があり、それぞれが分化するためのサイトカインや、分化した後のTh1 細胞や Th2 細胞が分泌するサイトカインの種類が異なる。そこでその違いが分かりやすいように表にしたものなどがあるが、これが記憶しずらい。分化するサイトカインや分泌するサイトカイン、などの概念が共通しているために干渉を起こしてどっちがどっちだったか混同してしまうからだ。

こういう時はTh1とTh2の対比をせずに Th1 に関する記憶が定着するまで意識的に Th2 の情報はインプットしないようにするといい。Th1 についてだけ徹底的に検索したり文書を読んだりして知識を得るのだ。Th1 の知識が確定していれば Th2 の知識は Th1 のアナロジーとして逆に理解しやすくなるだろう。

記憶をするときは印象をはっきりさせるために、類似の観念からの干渉を避けるべきだ。



[PR]
# by tnomura9 | 2017-03-11 09:33 | 考えるということ | Comments(0)

疑問を維持する

記憶は本質的に忘却するものなので繰り返し記憶することが大切だ。しかし、何を繰り返し見返すのかというと本を読んで自分が感じた疑問点を繰り返すのが一番効果的だ。

本をざっと眺めながら思いついた疑問点をメモ帳に記録していく。そうしてそのメモ帳を何度も見返すのだ。見返すときにその問いに答えることできるのか検討する。また、その問いから新しい疑問点が出てくればそれをまた書き留める。そうするうちに段々とどうしても知りたいと思う疑問が固まってくるので、それから初めて本文をしっかり読むようにする。疑問が沸かないうちは、参考書はパラパラと雑誌をめくるときの要領で眺めるだけにしておく。

疑問がはっきりしているときは、読解力もついているものだ。繰り返しは、本の内容ではなく自分の疑問について行うべきだ。


[PR]
# by tnomura9 | 2017-03-10 10:48 | 考えるということ | Comments(0)

ザッピング

ザッピングとはテレビを視聴するときにリモコンで頻繁にチャンネルを切り替える行動をいう。語源はリュックサック(zap)を背負って野山を気ままに散策することらしいが、一緒にテレビを見ている人には迷惑な話で、奥さんから我慢できないと避難されたり、心理学者からはストレスが溜まっているからだと断定されたりしている。しかし、これは動物行動学で言う探索行動の一種なのではないだろうか。

探索行動とは動物や幼児が周囲の状況を探索する行動のことである。実験室のネズミなどの場合も、迷路学習用の迷路に報酬をおかないで放しても、あちこちと移動して迷路の探索をする。また、このような探索行動を先に行ったネズミは迷路の先に報酬をおいた場合も学習の速度が速い。おそらく、探索行動によって脳の中に空間地図を作成しているのではないかと思われる。

探索行動の特徴は、行動にこれといった目的がないということだ。気ままに周囲を歩き回って、その状況を探索する。目的のない行動の特徴は、心理的なエネルギーが低く疲れをあまり感じないところだ。先程のザッピングにしても、パソコンやスマホによるウェブの散策にしても飽きずに長時間続けることができる。探索行動は思考活動と言うよりはもっと本能的なものだからかもしれない。

この疲れにくいというザッピングの特徴は参考書を読むときに利用できるだろう。要するに、特に読むという意識もなく本のページをあちこちと捲ってみるのだ。興味が湧けば読めばいいし、そうでなければさっと通り過ぎる。何かを学ぶという目的意識はおいておいて、とりあえず気ままに散策するのだ。そうしているうちにその本の空間的な情報が自然に頭の中に入ってくる。これは、あとで本格的にその本を読解するときに随分と助けになる。意識して読むわけではないので1回のザッピングで頭に残るものは少ないだろう。したがって、暇があれば何回も繰り返すことになる。

ザッピングは探索行動という本能的な行動であるので、精神エネルギーをあまり消費せず情報の探索ができる有効な方法のような気がする。

[PR]
# by tnomura9 | 2017-03-07 05:36 | 考えるということ | Comments(0)

Haskell やってない

このところ Haskell を全くやっていなかったので、覚えているかどうか ghci で試してみた。

Haskell で嬉しかったのは何と言っても高階関数だったので、

Prelude> map (*2) [1..10]
[2,4,6,8,10,12,14,16,18,20]

関数の合成はパイプライン感覚でできる。

Prelude> sum $ map (*2) [1..10]
110
Prelude> (\x -> x `div` 5) $ sum $ map (*2) [1..10]
22

ghci で複数行の入力をする時の定番。let 関数は IO モナドの let なので注意が必要。

Prelude> :{
Prelude| let
Prelude| fact 0 = 1
Prelude| fact n = n * fact (n-1)
Prelude| :}
Prelude> fact 5
120

標準関数の中でも分かりにくいのが foldr と foldl なので可視化してみた。

Prelude> foldr (\x y -> "(" ++ show x ++ "*" ++ y ++ ")") "0" [1..10]
"(1*(2*(3*(4*(5*(6*(7*(8*(9*(10*0))))))))))"

Prelude> foldl (\x y -> "(" ++ x ++ "*" ++ show y ++ ")") "0" [1..10]
"((((((((((0*1)*2)*3)*4)*5)*6)*7)*8)*9)*10)"

if .. then .. else 制御文

Prelude> let fact n = if n == 0 then 1 else n * fact(n-1)
Prelude> fact 5
120

ガード

Prelude> let fact n |n == 0 = 1| otherwise = n * fact (n-1)
Prelude> fact 5
120

case 式

Prelude> let fact n = case n of {0 -> 1; _ -> n * fact (n-1)}
Prelude> fact 5
120

結構色々覚えていたので安心した。結局のところ Haskell の使い方より、Haskell を何に使うかを思いつかないのが問題のようだ。

[PR]
# by tnomura9 | 2017-03-05 21:26 | Haskell | Comments(0)

スキミングとスキャニング

スキミングとスキャニングは英文の速読法の用語だが、日本語の文章でもすぐにでも活用できる速読法だ。視野の拡張などという摩訶不思議な技術がいらず、普通の読書スキルの人でもすぐに使えるという意味でも秀逸な方法だ。

スキミングは文書の全文を読むのではなく、段落の冒頭の1行だけを読んで段落の残りの部分は読まないやり方だ。各段落の1行目だけを読んでいって文書全体の内容の概略を把握する。段落の先頭の行を普通に読んでいくだけなので特別な技術はいらない。普通の読み方をしている人でも文書の概要を素早くつかむことができる。

ただし、これには条件がある。それはその文書がパラグラフライティングという技術的な書き方をされていることという前提があるのだ。パラグラフライティングとは何かと一口に言うと、要素的な意味のまとまりをパラグラフで表現して、それを単位として文章を論理的に構成するというやり方だ。

パラグラフライティングでは、段落には原則的に一つの主題しか配置しない。そしてその一つの主題の要約を文頭の1文で表すのだ。パラグラフの最初にそのパラグラフの主題を要約する中心文を置き、そのパラグラフのあとの部分にはその中心文を補足する内容の文章を配置する。読み手は中心文を読むことでパラグラフの内容が推測でき、あとの部分を読むことで予測した内容の詳細を知ることができる。

さらに、パラグラフライティングでは段落の配置も極力論理的に展開することを推奨している。段落が論理的に配置されていれば、一層文章の概要を把握するのが容易になる。

このようなパラグラフライティングで記述された文書は、段落の冒頭の文だけを読み進めることで、その文書の概要や構造を把握することができる。文書がパラグラフライティングで書かれていないときは、スキミングの効率は悪くなるだろう。

次にスキャニングの方だが、これはいわゆる拾い読みだ。自分の関心のある事柄に関することのみを拾い読みするやり方だ。自分にとって役立つ1行の文があればその本を読む価値があるとよく言われるが、そういう観点からは、スキャニングはずばり本の美味しいところだけを攫う方法だ。

スキミングとスキャニングは特殊な訓練のいらない優れた速読法だが、それが効果を上げるためには文書の側で制御された論理的な記述がされている必要がある。

[PR]
# by tnomura9 | 2017-02-28 18:11 | 考えるということ | Comments(0)

指でなぞる

昔の速読術では読んでいる行を指でなぞるように勧められていた。後では非効率的だということで推奨されなくなったが、最近参考書を読むのに指を使って読むようになったら疲れなくなった。

具体的にどうしているのかというと、キーワードの箇所を指で押さえて、それについて思いつくことをぼんやりと思い出すようにしてから本文を読み進めるようにしている。キーワードについて何個か関連の知識や、疑問を想起できるまで指を勧めないようにするのだ。

また、図譜があれば、構造図の関連を指でなぞっていったり、解剖の図譜の血管の走行を指でなぞったりしていく、また、立体的な図譜の場合は指でその立体をなぞっているようなイメージを作ってみる。

目で読むのが早いが、指でその速度をわざとゆっくりすることで、理解力の方はかえって増すような気がする。

[PR]
# by tnomura9 | 2017-02-21 10:19 | 考えるということ | Comments(0)

エクソソーム (exosome)

エクソソーム (exosome) というのは耳慣れない言葉だが、細胞が細胞質の物質を脂質膜に包んで放出したものだ。基本的には脂質膜に覆われた細胞質の一部だが、中にRNAの断片などを含んでいるらしい。30年前に発見されたが、以前は細胞が不要なものを輩出したものだと考えられて重要視されていなかった。

ところが近年このエクソソームに含まれる RNA が他の細胞に伝達され、その細胞の働きに影響することが分かり、細胞と細胞の間の情報伝達の機能をはたしていることが分かってきた。

特に注目されるのが癌とのかかわりだ。エクソソームには癌特有の RNA が含まれるため、早期の癌を血液検査で調べることができるかもしれないと期待されている。また、癌は生存するために必要な微小循環を作り出さなければならないが、癌細胞から分泌されるエクソソームが周囲の正常細胞を刺激し血管新生を誘発していることがわかり、癌の治療の面からも注目されている。

ポリペプチド、機能性脂質、神経伝達物質、サイトカイン、ホルモン以外にもエキソソームによるRNAの伝達で細胞間の情報伝達が行われているようだ。

[PR]
# by tnomura9 | 2017-02-14 11:24 | 話のネタ | Comments(0)

超常現象の謎解き

退屈なので携帯をいじっていたら次のサイトに出会った。


世に超常現象と騒がれている現象について調査して謎解きをしているサイトだ。この中で超古代・オーパーツについての一連の記事が面白かった。エーリッヒ・フォン・デニケンの『神々への帰還』を興奮して読んだ者にとっては寂しい限りだが、きっちりと謎解きがされている。現代文明を凌ぐ超古代文明があったのならどこかで古代の機械や建物の残骸が発掘されても良さそうだがどうしてないのだろうと思うこともあったので、納得できた。

パレンケ遺跡の碑文のピラミッドの地下に水路が見つかったり、テオティワカンのピラミッドの下に地下道があり多量の水銀が見つかったりなど、古代のロマンには事欠かないが、超古代文明は見つかっていない。

ただ、アトランチスについては、スベイン南部のアンダルシア地方のドニャーナ国立公園にあるのではないかという説に注目している。都市が三角州に作られていたこと、アトラスの柱(ジブラルタル海峡)の向こうにあったこと、タルシッシュ(タルテッソス)という青銅と造船で有名な古代都市が聖書にも記述されていることなどと符合するので発掘を楽しみにしている。それでも、宇宙船やレーザー兵器を作ったりするような超古代文明ではなさそうだが。

タルテッソスには未解読のタルテッソス文字があるが、これがアイルランドのケルト語ではないかという説がある。遺伝子解析でアイルランドの人のDNAとスペイン南部の人のDNAが近縁であるらしい。イギリスは錫の島と呼ばれており、タルテッソスはそこに産する錫を独占的に扱っていたらしいのであり得る話だ。タルテッソス文字がケルト語として解読されたら面白いだろう。

[PR]
# by tnomura9 | 2017-02-09 00:24 | 話のネタ | Comments(0)