2013年8月27日火曜日

xmonadとHaskell(その2)

設定してみる


これを見れば、少し何かのプログラムをしたことがあるなら、Haskellを知らなくても、{}の内部でキーワードに対応して何かを設定していることがわかる。

実際に、teriminal =の右側の文字列を、"xterm"とか"gnome-terminal"とか自分の持っているものに変えてみる。

modMask = の右側には mod4Maskを指定してある。これは、ウインドーズキーに割り当てられている。デフォルトはmod1Maskでaltキーに割り当てられている。

設定を変えた後は win + q で新しい設定に更新される。



ここで、xmonadの設定の基本の一つは、簡単に言えば、この{}の中にある各項目を設定していくことにある。


上の例のxmonad.hsには3個の項目しかないが、設定すべき項目は全部で15個の項目がある。上の例で設定されている項目の値らしきものは、文字列やシンボル、数字なので初めて見た人でもわかるが、この他の項目には、何を言ってるのかわからない値もみられる。

/usr/share/xmonad-0.11/man/xmonad.hs

上のファイルには、すべての項目のデフォルトの値が示されているかもしれない。



改めて、構文をみてる。

main = xmonad defaultConfig { .... }

これは、xmonad関数に「defaultConfig {...}」で示される値を引数として渡すことを定義している。

defaultConfig {....} は一つの値を示している。


値ってなんだろう?

よく見る、値って"xterm"とか、mod4Maskとか、3とか普通に値っぽく見える。

しかし、Cなんかの構造体やら、Javaやrubyのオブジェクトやらでは、いくつかの要素をひとまとめにして一つのものとして扱えたりする。例えば、「名前」、「性別」、「体重」の3つが纏まって、ひとつの「人間」という値を表したりする。

そしてこれは、単なる"xterm"よりも、なんだかちょっとかっこ良いオブジェクト指向チックで複雑な値にもみえる。

でも、よく考えてみれば、「人間」を表す時に「名前」のみで構成されていれば、単なる"xterm"な値と変わらない。要素がひとつからなる値の方が特殊なのかもしれない。


Haskellの「型」

Haskellにも見慣れた「型」がある。
整数を表すInt、実数を表すFloat、文字を表すChar、真偽値を表すBool。

また、自作の型を定義することが出来る。
Bool型の定義で構文を大まかに例示すれば以下の通り。

data Bool = False | True
 dataキーワードに続けて「型名」を書く。ここではBoolが「型名」

そして、イコールの右側に、取り得る値の種類を定義する。|(縦棒)を使って「または」としてどんどん繋げる。つまり、Boolは「False」っていう値の種類、または、「True」っていう値の種類をとる。

ここで定義されているFalseは「値」そのものではなくて、「値の種類」であることに注意。そして、これを「値コンストラクタ」と呼ぶことを覚える。


コンストラクタは、インスタンスを作るときのアレだ!
すなわち、値コンストラクタっていうのは、値を作る関数と同じ物の事。

ここで、さっきの「人間型」を定義してみる。

<その1>
「人間」を表すのに「性別」っぽいもので、値の種類を分けてみた。
「男」、「女」、「男の娘」の3種類

data Human = Otoko | Onna | Okama

種類分けだけだと、False、TrueのBool型に似てる。


<その2>
しかし、実はOtoko、Onna、Okamaは関数なので、 引数を取ることが出来る。
なので、実は以下のような定義が出来る。
「男」を構成する要素として「名前」をString、「度胸」度をIntで表す。
「女」を構成する要素として「名前」をString、「愛嬌」度をIntで表す。
「男の娘」を構成する要素として「名前」をString、「最強」度をIntで表す。

data Human = Otoko String Int | Onna String Int | Okama String Int


これを踏まえて、もういちどBool型の定義に戻ってみる。
data Bool = False | True

他の言語で見慣れたFalseやTrueは値そのものを示すリテラルなシンボル的なものかもしれないけれど、Haskellの世界ではFalseもTrueも引数を取っていない値コンストラクタであり、それは引数が0個の関数である。
なので、値とは、Falseそのものではなく、そのコンストラクタの評価結果であると考える。

そうそう、最後に約束事として、型名も値コンストラクタも大文字で始まらなければならない。

値を作る

これまでは型を定義する話。
実際に定義された型の値は次のように作る(定義する)。

hoge :: Bool
hoge = True

なんだよ、結局、書き方は他の言語でみてるのとおんなじじゃん!!とか言わない。
Trueは値コンストラクタで関数。

上記の式は、「hogeという変数に、Trueを代入」しているように見えるが、Haskellではそうではないらしい。「純粋関数型プログラミング言語」っていうのは、まだよくわからないけれど、同じものに対する関数の結果はいつも同じであるはずなため、中身が変わることを意味する「変数」とか中身を入れ替える行為になる「代入」とかいう概念がそもそも無さそうな感じ。

では、Haskellな人はどう読んでいるのか?
「hogeをTrueと定義する」みたいな感じ。

何が違うの?じゃなくて、まずは、そう感じるんだ!と心の中で唱える。
じゃ、変数じゃない「hoge」ってなにかといえば、単なる「名前」。小文字ではじまってるのは、何かを表す「名前」なのだ。
「hogeってのはBool型の何かだよ」っていって、Bool型のTureが示す値で定義してる。

まぁ、「=」があると 何かを「代入」じゃなく「定義」してるって思えるようになる努力をするとHaskellが理解できるようになるといいなって思ってる。


それはさておき、次に、人間を作ってみる。

dareka :: Human
dareka = Otoko "taro" 10

なんとなく、人間っぽいのを作ってる感じのする式になった。

しかし、"taro"が名前で、10が度胸度を表しているとは一見してわからない。
Haskellの型の場合上で見たように、単に値コンストラクタとそれに続く引数の位置
によって、要素を識別することになる。

 一方、オブジェクト指向言語の場合、要素についてはプロパティとして、その名前がついていて値との関連性が分かりやすい。


つまり、

name = "taro"
dokyou = 10

とかいう分かりやすい書き方がHaskellにはないのかな、、、、ってどっかでみたような?

terminal = "urxvt"
modMask  = mod4Mask

忘れてたかもしれないけれど、これの話をしてたんだよね。

型の定義「レコード構文」

型の定義において、先に書いた構文とは別に、値コンストラクタが複数の引数を取る時、その引数が何を表すのかわかりやすくするための構文、「レコード構文」がある。

型の定義において、値コンストラクタの引数部分に中括弧を用いて、その中に、要素の名前を定義する。
値として定義する時には、値コンストラクタの引数部分に中括弧を用いて名前に対して「=」を使って要素となる値を定義する。

この、オカマの最強度9999を持つつばさちゃんは、xmonadの設定defaultConfigと同じようにみえる。

つまり、逆に言えばdefaultConfig {...}は、やっぱりこれでひとつの値なのだ。


0 件のコメント:

コメントを投稿