人気ブログランキング | 話題のタグを見る

付箋に問題を書く読書法

前回の記事から読書に付箋を使う方法が面白くなってきたのでもう少しやってみる。今回やってみたのは、参考書の本文についての質問を付箋に書いて、本文の記述の答えに相当する部分に貼付ける方法だ。

使う付箋は 75mm × 12.5mm のポストイットを使った。これだと問題と言っても一行でせいぜい20文字しか書き込めない。それでも十分なのだ。じっさいにどのようにやってみたのかを説明した方が速いので『RailsによるアジャイルWebアプリケーション開発』 David Thomas and David Heinemeier Hansson 著の一部分を引用する。
このコードはどこに記述すればいいでしょう? エラーメッセージを表示したいのはページの一番上なので、カタログ表示テンプレート (index.rhtml) のコードの先頭に記述できなくもありません。しかしアプリケーションの開発は続きます。すべてのページで同じようにエラーメッセージを表示できた方がいいでしょう。このアプリケーションでは、ストアの全てのページを一貫性のある形で表示するために Rails のレイアウトを使っています。フラッシュを処理するコードもレイアウト内に追加しましょう。これで、エラーの表示位置をサイドバーに変更したいと顧客から突然言われても、1つのファイルに手を加えるだけですとあの全ページの表示が更新できます。この修正を加えたストアのレイアウトコードは次のようになります。
長い例文を入力したくなかったのでこれを選んだのだが、脈絡もなくぱっと開けたページだったので、これでも十分に分かりにくい。そこで、先ほどのポストイットに「エラーメッセージをどこに表示?」と書き込んで答えをさがした。どうやら Rails のレイアウトを使っていますという箇所のようだったので、それをそこに貼った。

そうして再度文章をながめていると、最初のほうでは「エラーメッセージを表示する場所をテンプレートにするのはあまり良くない」と主張しており、また、「エラーメッセージは統一的に表示した方がいい」、「ページのレイアウトを換えてもコードの修正が簡単にできないといけない」などの理由で、エラーメッセージの表示場所をテンプレートではなくレイアウトに記述するよう勧めていることが分かる。

75mm × 12.5mm のポストイットに書き込めるような小さな質問をひとつ作るだけで、突然に全体の文章の構造が見えてきた。例文だけでなく、実際の参考書でやってみると、大体本の1ページに2つくらいの質問を書いたポストイットを貼付けるだけで、そのページに書かれている内容の構成がはっきり分かるようになる。

質問や問題を書き込んだ付箋の威力おそるべしだ。貼る前は単に文字の並んだ平面だった文書がたった2枚のポストイットを貼るだけで、突然に立体的な構成を持った町並みのように見えてくる。

結局のところ本に書かれている文章は読者の頭の中で再構成されなければ理解されないのだ。そうして、読者が文章を読んでその情報を頭の中に再構成するためのきっかけは、「なぜ?」とか「これは何?」などの質問なのだ。それを本文に貼ったおかげで、脳はポストイット周辺の情報の構成を頭の中に再構成する準備ができたのだろう。

難しい内容や分かりにくい文章を読解するときにはおすすめの方法だ。

追記

本文を読み返すときも、付箋の問を見たほうが内容を思い出しやすい。1ページの付箋の数も特にこだわらなくてよい。疑問に思ったことは何でも付箋に書き付けてとりあえず貼っておく。

付箋に書く問いは単に本文のキーワードを想起させるものよりも、内容を論理的に推測させるものの方が効果的だ。たとえば、重要項目が4つあったとき、「重要項目はいくつか?」という問いよりは、「なぜ、重要項目が4つなのか?」とか「4つの項目の間に意味の関連性はあるのか?」などというように、著者の動機を推測するような内容のものがよい。

「なぜ、これがここにあるのか?」という推理的なアブダクションの問いは、読書に限らずいろいろな場所で有効なので日頃から訓練しておく必要がある。
# by tnomura9 | 2014-03-07 22:59 | 考えるということ | Comments(0)

付箋紙速読法

小説を読むときは別として、本を読むときに先ず最初にするのはスキミングだ。雑誌をめくるときのように本のページをぱらぱら眺めていく事だ。挿絵や図解があるときはそれに注目してもいいし、文字だけなら見出しや強調文字のところをさっと眺める。詳しく読もうとすると疲れるのであくまでもさっと流していく、そうやってその本に自分をなじませていくのだ。

次にやるのは、目次を眺めて本の構成をみたり、スキミングで気になった挿絵や図解の説明を読んだりして、大まかな内容を把握していく。

それからおもむろに最初の章から読み始める。

普段はこの順番で読んでいたのだが、最近もうひとつの読み方を見つけた。それは、付箋紙をつかうやり方だ。

本文の見開きのなかで気になったキーワードをひとつだけ付箋紙に書いて、見開きの右のページの小口に張っていくのだ。キーワードは付箋紙の右端に書き、本を閉じても見えるように小口からはみ出させて付箋紙をはっておく。次のページの見開きに対しても同じようにするが、前の付箋紙と重ならないように下へずらして貼る。

この作業を続けていくが、章が変わったら付箋紙は小口の一番上の天に接するところから貼り始める。

付箋紙に書くキーワードはできるだけ見出しではない方がいい、本文の中の具体的な、あるいは細部に関わるキーワードを選んだ方がいい。見出しは本文の要約をするために抽象的になりやすく、それを後で見ても詳細を思い出せないからだ。むしろ記述の詳細に関わるようなキーワードを狙うのがコツだ。

また、付箋紙を貼る作業のときはあまり本文を読み込まない方がいい。脳が疲労して続けられなくなるからだ。

ページの最後まで付箋紙を貼っていったら、それからが本番だ。付箋紙に書き込まれたキーワードを見てその見開きにどんな事が書かれていたのかを思い出すのだ。そうすると、不思議とそのページの内容や本の構成が自然に理解できてくる。また、キーワードを眺めてあれこれ考えているうちに自分の知りたかった情報が何だったのかが自然と見えてくる。

それから、あらためて本を読み始めると不思議とよくわかるようになっている。最近、必要になった情報が付箋紙を貼っておいたおかげで読んでもいなかったのにすぐに取り出せてうれしかったのを経験した。

見開きページにキーワードをひとつだけというのは不安になるかもしれないが、脳は一度にはそうたくさんの情報を入力できない。それに大切なのは本に何が書いてあるかよりも、脳のネットワークの中にその知識がどう組み込まれているのかということだ。したがって、思い出すことの方に重点が置かれなくてはならない。キーワードをヒントにして、何を考え、何を思い出すのかということが大切なのだ。

疑問や問題意識のない状況では、情報は覚えたとしてもすぐに忘れ去られてしまう。頭のなかの探索行動を引き起こすためのきっかけとしてキーワードを使うのであって。羅列された重要単語を覚えるためのキーワードのピックアップではない。

本というものは一回読んだくらいでは頭には残るはずがない。繰り返し反芻しながら次第に咀嚼されていくという意識が必要だ。
# by tnomura9 | 2014-03-05 00:35 | 考えるということ | Comments(0)

smart constructors その6

前へ 目次 次へ

参照: cabal-instsll 関連のリンク Distribution.Simple.Commnad Distribution.Simple.Setup

引き続き、Distribution.Simple.Command の OptDescr smart constructors セクションを見てみる。最初に今回の記事を ghci で試すための準備をする。

Prelude> :set prompt "ghci> "
ghci> import Distribution.Simple.Command
ghci> import Distribution.Simple.Setup
ghci> import Distribution.ReadE
ghci> import Data.Monoid

choiceOpt

Distribution.Simple.Command に定義されている choiceOpt のコードは次のようになる。

-- | create a Choice option
choiceOpt :: Eq b => [(b,OptFlags,Description)] -> MkOptDescr (a -> b) (b -> a -> a) a
choiceOpt aa_ff _sf _lf _d get set  = ChoiceOpt alts
    where alts = [(d,flags, set alt, (==alt) . get) | (alt,flags,d) <- aa_ff]

[(b,OptFlags,Description)] を引数にとり MkOptDescr 型の関数を返す関数だ。[(b,OptFlags,Descriptio)] は今まで調べてきた結果から考えると (フラグの値, (ショートオプションのリスト, ロングオプションのリスト), オプションの説明) という三組のタプルのリストだ。コードも難しくはない。引数のリストの三組のデータを利用して (オプションの説明, (ショートオプションのリスト, ロングオプションのリスト), フラグセットのフラグに値をセットする関数, フラグセットのフラグの値を取り出す関数) というタプルのリストを作成するだけだ。

そうはいっても実例がなければ分かりづらい。さいわい choiceOpt の実例は installCommand のコードの中に見つけることができた。Distribution.Simple.Setup の installCommand のコードは次のようになる。

installCommand :: CommandUI InstallFlags
installCommand = makeCommand name shortDesc longDesc defaultInstallFlags options
  where
    name       = "install"
    shortDesc  = "Copy the files into the install locations. Run register."
    longDesc   = Just $ \_ ->
         "Unlike the copy command, install calls the register command.\n"
      ++ "If you want to install into a location that is not what was\n"
      ++ "specified in the configure step, use the copy command.\n"
    options showOrParseArgs =
      [optionVerbosity installVerbosity (\v flags -> flags { installVerbosity = v })
      ,optionDistPref
         installDistPref (\d flags -> flags { installDistPref = d })
         showOrParseArgs

      ,option "" ["inplace"]
         "install the package in the install subdirectory of the dist prefix, so it can be used without being installed"
         installInPlace (\v flags -> flags { installInPlace = v })
         trueArg

      ,option "" ["shell-wrappers"]
         "using shell script wrappers around executables"
         installUseWrapper (\v flags -> flags { installUseWrapper = v })
         (boolOpt [] [])

      ,option "" ["package-db"] ""
         installPackageDB (\v flags -> flags { installPackageDB = v })
         (choiceOpt [ (Flag UserPackageDB, ([],["user"]),
                      "upon configuration register this package in the user's local package database")
                    , (Flag GlobalPackageDB, ([],["global"]),
                      "(default) upon configuration register this package in the system-wide package database")])
      ]

このコードの最後の部分に choiceOpt 関数が利用されている。

installCommand は CommandUI 型のデータなので次のような構成になっている。

gchi> :info CommandUI
data CommandUI flags
  = CommandUI {commandName :: String,
               commandSynopsis :: String,
               commandUsage :: String -> String,
               commandDescription :: Maybe (String -> String),
               commandDefaultFlags :: flags,
               commandOptions :: ShowOrParseArgs -> [OptionField flags]}
        -- Defined in `Distribution.Simple.Command'

そこで choiceOpt を利用して作成された OptionField 型のデータは次のようにして取り出すことができる。

gchi> let foo = last $ (commandOptions installCommand) ShowArgs

gchi> :info foo
foo :: OptionField InstallFlags -- Defined at :15:5

OptionField 型のデータの構成は次のようになるので、

gchi> :info OptionField
data OptionField a
  = OptionField {optionName :: Name, optionDescr :: [OptDescr a]}
        -- Defined in `Distribution.Simple.Command'

foo のオプション名を次のように調べることができる。

gchi> optionName foo
"package-db"

そこで optionDescr アクセサで OptDecr 型のリストを取り出すことができる。

gchi> :t optionDescr foo
optionDescr foo :: [OptDescr InstallFlags]

このリストの中の要素数を調べてみたが、1個の OptDescr 型のデータのようだ。

gchi> length $ optionDescr foo
1

これを取り出して bar にバインドした。

gchi> let bar = head $ optionDescr foo

gchi> :t bar
bar :: OptDescr InstallFlags

bar は choiceOpt を利用して作成した OptDescr 型のデータなのでコンストラクタは ChoiceOpt になるはずだ。ChoiceOpt の構成は次のようになる。

gchi> :t ChoiceOpt
ChoiceOpt
  :: [(Description, OptFlags, a -> a, a -> Bool)] -> OptDescr a

そこで、パターンマッチで ChoiceOpt のパラメータを取り出して baz にバインドした。

gchi> let (ChoiceOpt baz) = bar

baz の要素数を調べた所2個だった。

gchi> length baz
2

そこで baz の要素の内 Description と OptFlags を取り出してみた。

gchi> [(d, flags) | (d, flags, set, get) <- baz]
[("upon configuration register this package in the user's local package database",("",["user"])),("(default) upon configuration register this package in the system-wide package database",("",["global"]))]

baz の先頭の要素の set 関数と get 関数をとりだしてみた。

gchi> let (_, _, set, get) = head baz

gchi> get defaultInstallFlags
False
gchi> get $ set defaultInstallFlags
True

このように、ChoiceOpt コンストラクタのパラメータのリストの要素のタプルは
  1. オプションの説明
  2. ショートオプション文字のリストとロングオプション文字列のリストからなるペア
  3. フラグセットのフラグの値を設定する関数
  4. フラグセットのフラグの値を読み出す関数
からなっていることがわかる。

これらの情報は OptDescr 型のデータに根本的なもので、他の OptDescr 型のコンストラクタのパラメータにも必ず含まれている。:info OptDescr とするとその様子をみることができる。

ghci> :info OptDescr
data OptDescr a
  = ReqArg Description
           OptFlags
           ArgPlaceHolder
           (ReadE (a -> a))
           (a -> [String])
  | OptArg Description
           OptFlags
           ArgPlaceHolder
           (ReadE (a -> a))
           (a -> a)
           (a -> [Maybe String])
  | ChoiceOpt [(Description, OptFlags, a -> a, a -> Bool)]
  | BoolOpt Description
            OptFlags
            OptFlags
            (Bool -> a -> a)
            (a -> Maybe Bool)
        -- Defined in `Distribution.Simple.Command'
ghci> :info OptFlags
type OptFlags = (SFlags, LFlags)
        -- Defined in `Distribution.Simple.Command'

OptDescr 型のデータには、このように、オプションをパースして、コマンドの動作をコントロールするフラグセットの値を操作するための情報が詰め込まれている。

ここで再度 CommandUI 型の構成を見てみよう。

data CommandUI flags
  = CommandUI {commandName :: String,
               commandSynopsis :: String,
               commandUsage :: String -> String,
               commandDescription :: Maybe (String -> String),
               commandDefaultFlags :: flags,
               commandOptions :: ShowOrParseArgs -> [OptionField flags]}
        -- Defined in `Distribution.Simple.Command'

CommandUI 型の commandName ~ commandDescription までのフィールドはユーザへの情報提供のための文字列データだ。commandDefaultFlags フィールドに収められているのはそのコマンドの動作を制御するためのデフォールトのフラグセットだ。そうして、commandOptions フィールドには OptDescr 型のデータを含む OptionField 型のデータのリストが収められる。ここには、オプションをパースしてそれに対応するフラグセットを作成するための情報が詰め込まれているのだ。

commandsRun 関数は CommandUI 型のデータと Command action 型のデータのリストと、コマンド・ラインから getArgs 関数で取得したコマンドラインオプションのリストを引数に取り、コマンド・ラインオプションをパースして、コマンドのフラグセットと CommandPars action 型の関数のペアを (CommandPars にラッピングして) 戻値として戻す。この過程にどのように OptionField 型のデータやそれに含まれる OptDescr 型のデータが利用されていくのかを知るのが次からの記事の関心の中心になる。

commandsRun ::
  CommandUI a
  -> [Command action]
  -> [String]
  -> CommandParse (a, CommandParse action)
        -- Defined in `Distribution.Simple.Command'
# by tnomura9 | 2014-03-02 18:53 | Haskell | Comments(0)

積んどく本の処理のしかた。

机の上には読まないといけない本が積み上げてある。邪魔だが、本棚にしまってしまうとそのまま読まなくなってしまうのではないかとという気がするので、そのままにしているが邪魔なことこの上ない。

なんでそういうことになるのだろうと考えてみたが、要するに本を読むのは結構たいへんだからだ。脳もフル回転しないといけない。おまけに、必要な情報を理解できないかもしれないという鬱陶しさもある。それに読んでない本は文字の羅列で、ページに色がついていない。

こういうときは目次を読むことを勧められているが、基礎知識がほとんどない分野の目次を読んでも内容の予測をできることはあまりない。目次の項目の関連性や重要度が読めないからだ。

そこで、目次や見出しに色をつけてみることを考えてみた。それぞれの項目の横に次のような文字を書き込むようにしたのだ。
  1. A は内容が則、実務に役立つ場合。
  2. C は実務には利用しないが知識として知っておきたい概念
  3. P は専門的に必要になる細かい記述
  4. T は使わないであろう知識

例えば薬の添付文書であれば、A は適応症や用法用量、P は他の薬剤との相互作用や、血中濃度の半減期、C は薬剤の化学構造や作用部位などになるだろう。

分け方は各人の好みでいいと思うが、知識を素早く役立てたい場合に、項目を見てざっとその性格を思い出すための工夫だ。

T は trash can からとったのだが、本を全て読んで理解するのは時間的にも能力的にも無理なのに、本があるとどうしても全てを読みたくなってしまう強迫観念を捨てるための記号だ。つらいことだが、無理なことはやはり無理だ。

実際に数年積んどくしていた参考書に使ってみたが、見出しに上のようなタグ付けをしたところ、自分が何を読もうとしているのかがよくわかり、無事に本棚行きにすることができた。

実際に使えそうな知識には A をつけて精読し、細かいテクニックは P をつけてざっと流すだけにした。また、理論的なことは C にして、A の項目と関連の深そうなところだけを真剣に読んだ。また、重要な項目は付箋を貼ってコメントをつけておいた。これはこの本を読んだということが本を眺めただけでわかるので便利だった。

よく考えたら他の人は既にやっている工夫だった。今まで気が付かなかったのはそれだけ勉強をサボっていたのを反映している。
# by tnomura9 | 2014-02-25 12:58 | 考えるということ | Comments(0)

実数直線上には一点は存在しない。

アキレスと亀のパラドックスや、飛ぶ矢のパラドックスなどゼノンのパラドックスはどちらも連続性の矛盾に関連するものだ。連続性の矛盾というと専門家に叱られるかもしれないが、連続性の定義から推論する限り連続体には一点というものは存在しないという結論になる。

抽象的になるのを避けるために実数直線について考えてみよう。実数直線上では異なる2点の間には必ず2点と異なる別の点を見つけることができる。

実数直線上で他の点との重複のない一点があると仮定する。それを仮に点 p とする。点 p は唯一であるということは点 p が他の点とは重複が全くないということである。すなわち点 p は実数直線上のどの点とも重ならない。

ここで、実数直線上で点 p とは異なる全ての点を集めた集合を Q とする。そうすると集合 Q の要素である実数上の点は点 p との距離によって分類することができる。そこで、そのうち点 p に最も近い点を q とする。しかし点 q は点 p とは異なっている。そうすると実数直線の連続性から点 p と点 q の間に点 r が存在するはずだ。しかし、これは点 r が点 q より点 p に近くなり集合 Q には含まれない。これは集合 Q が点 p 以外の全ての点の集合であるという過程に反する。したがって、結論が矛盾しているので、実数直線上に一点が存在するという仮定が誤りであることが証明される。

これには結論の矛盾がしめすのは点 p とは異なる全ての点の集合には点 p に最も近い点が存在しないということを意味するだけで、点 p が存在しないということを意味するのではないという反論があるかもしれない。デデキントの切断だ。しかしそうなると集合 Q は点 p に限りなく近づく点を要素として含んだ無限集合ということになるのだろうか。

点 p が存在しないという立場と、点 p に無限に近づく点を要素として持つ無限集合 Q が存在するという立場は、実数直線の性質を別の眺め方で見ているにすぎないように思える。

単純に実数直線上には点はなく、無限に縮小する区間で点という概念を表すのだと考えたほうが、ゼノンのパラドックスに対する反論を作りやすいのではないだろうか。

アキレスと亀のパラドックスで言うとアキレスと亀の観測時点は点ではなく微小な区間であるから、アキレスが亀に追いつく可能性を排除できないと反論できるし、飛ぶ矢のパラドックスでは、瞬間という点は存在せず無限小の区間であると考えるべきだと反論できる。

もちろんそれでも連続とは何かという疑問は残ってしまうが。

追記

この議論のポイントは、「隣り合う2点の間に必ず点が存在する」という連続性の定義が、一点を他の点と区別することを不可能にしているということだ。実数に埋め込まれた整数は一点だというかも知れないが、たとえば 1 という整数でも実数直線上にあるときには実数直線上の 1 の近傍の点と区別することは不可能になる。1 という点が実数上の他の点とは全く重ならないユニークな点であるということを主張できなくなってしまうからだ。

円周率の小数点表示の最終的な値が永遠に求められないように、1 と 1.000... と 0.999... の差も永遠に求めることはできない。

こういう意味でも実数に整数の一点という考え方を簡単には当てはめられないことが分かる。実数における一点については本質的に不確実性を排除できないからだ。
# by tnomura9 | 2014-02-18 19:02 | 考えるということ | Comments(3)