2014年10月12日日曜日

Greedのカスタマイズ

TopCoderのArena用プラグイン「Greed」のカスタマイズに挑戦。




Greedは高機能なので、ほとんど何の設定をしなくても、Arena参戦するのに困る事は無い。
しかし、他のSRM参加者のソースを見ていると、ソースの初めに

#define REP(i, N) for (int i = 0; i < (int)N; i++)

とか書かれていたりする。
これが、なんか出来る人っぽくてカッコいいので自分でも使ってみたくなった。というより、きっと、こういうのは定番なので、ちゃんと技術を盗んでいかねばならないのだ!!


greed.confファイルの作成


Greedの導入時の唯一の設定項目は、workspaceディレクトリを設定することだった。
Greedの設定は、その指定したworkspaceディレクトリ内にgreed.confというファイルを作って行うことになる。なので、とりあえず、空のgreed.confを用意する。


カスタマイズ用のテンプレートファイルの作成

greed.confの次に、テンプレートファイルと呼ばれるファイルを用意する。

Greedは、アリーナから問題を開くことで、ローカルにソースやテストケースのファイルを作成してくれるが、この作成されるファイルのひな形をテンプレートファイルという。

そこで、デフォルトのテンプレートファイルに代えて、自分の好きなテンプレートファイルを作り、そのファイルをテンプレートファイルとして使いますよということをgreed.confで設定してあげれば目的が達成できるようだ。

まず、デフォルトのテンプレートファイル(C++用)の内容は以下の通り。

https://github.com/shivawu/topcoder-greed/blob/master/src/main/resources/templates/source/cpp.tmpl


このファイルをダウンロードして、「my_template.cpp」というファイル名にし、workspaceディレクトリに置く。このmy_template.cppを好きに書き換えることで、カスタマイズをする。


カスタマイズ用のテンプレートファイルとして指定する


先に述べた通り、カスタマイズ用のテンプレートを使うように設定するにはgreed.confに次の一行を書き込む。

greed.language.cpp.templateDef.source.templateFile = my_template.cpp

ここまでで、デフォルトと同じ状態のソースコードが生成される。


C++のマクロ


テンプレートファイルでは、${と}で囲まれた部分が、テンプレートエンジンによって置き換えが行われる部分で、それ以外の部分は、書いたらそのまま出力される。

なので、あまり難しく考えなくても、C++用のマクロは、テンプレートファイル前半部分にべた書きしておけばOK!


以前に紹介した、greedの設定を紹介してくれている人のページを参考にすると、インクルードファイルは#include <bits/stdc++.h>することで、必要そうな色々なものを呼び出してくれるらしいので、それにしてみた。

その他、C++の便利なマクロってどんなのがあるのかな?と思って検索してみると

TopCoderから学ぶ美しいマクロや型宣言 C++

というのが、みつかった。
そこで、初心者でもよく使いそうな奴だけ抜き出して整理してみた。



もっと使いこなせるようになったら、付け足していけば良いのかなと思う。

2014年10月7日火曜日

Greedというプラグイン


土曜日に「今日は思う存分、過去問を楽しもう!」と思ってTopCoderのアリーナ起動したら、過去問の数がいつもと違ってものすごく少ない。なんで??と思ってあれこれみていると、Active Contestsの欄に大会のお知らせのようなものが。

というわけで、TopCoderのSRM大会に初参戦!!

私は、練習問題を解く時には、Arenaで起動されるエディタを使って直接ソースを書いていたのだけれど、他の人のソースを見るとエディタのプラグインのコメントのようなものがあったので、そういうのがあるんだろうなとは思っていた。


Arena用のプラグインGreed


そこで、せっかく大会に出るんだから、環境も適当に整えよう!と思ってネットで検索。
どうやら、Greedというプラグインが評判良いらしい。
https://github.com/shivawu/topcoder-greed

そして、「これいいよー」と紹介している人のページ(日本語)
http://qiita.com/ororog/items/42a9032f20bd9d239f95


上でも書いた通り、SRMの問題に対する回答は、Arenaアプレットのフォームにプログラムを直接書き込むことで提出する。

しかし、このGreedプラグインを使うことで、問題に対する解答のためのソースファイルの雛形がローカル(自分のパソコン)に作成されるので、そのファイルを自分がいつも使っているエディタで編集することが出来るようになる。しかも、このローカルのソースファイルはGreedによってArenaと連動されているので、ファイルがローカルにあるということを意識せず、Arenaアプレット側のコンパイルやテスト、サブミットボタンを押すだけで、通常のアプレット上でのテストやサブミットが行われる。

また、ここで作成してくれるソースの雛形は、問題で指定されている提出用のクラスとメソッドを定義してくれるので、あとは中身を書くだけの状態になっている。そして、このソースはそのまま、ローカルでコンパイルして実行すると、問題に付随してくるテストケースをを試して、その結果を表示てくれるプログラムもつけてくれている。(提出時には、これらテストケースを実行するメイン部分は自動的に省いてくれるので、何も気にすることはない。)

更に更に、問題文をHTML形式にしたファイルもローカルのディレクトリに作成してくれる。Arenaのアプレットで読むよりも、いつも使っているブラウザで見る方が字も読みやすいし、翻訳とかもブラウザからのほうがしやすい。

すなわち、このプラグインは「とっても便利!Greed最高!」なのだ。


SRM初参戦日記


さて、そんな感じに、環境は万全に整ったのは良いが、肝心のプログラミング技術の方が素人。

その日までの間に、Div2 Easyの問題にいくつか挑戦していたが、C++のコンパイルってどうやるんだっけ?から始まって、vectorやstringのメソッドをネットで適当に検索しながらプログラムを書くというレベル、、、大体、問題の英語を読んで、問題を理解するのも時間かかるので、今回の大会は、まずは1問を時間内に解けることを目標にしようと思って、エントリー開始時間を待っていた。


エントリー開始は、午後10時。
同意書みたいなのに同意して、エントリー。

参加者の一覧みたいなのが見れるので、覗いてみると、あこがれのレッドコーダーは日本人にもいっぱいいた。というか、日本人の参加者が結構多いんだなぁという印象を受けた。白色のNON-RATEDの人は多分大会初挑戦なんだろうけれど、その時点では日本人の白色は3人程度で、なんとなく、怖気づく。。

大会開始5分前、午前12時55分頃。
チャット画面では、エントリー締め切りがアナウンスされ、なんとなくチャット画面ごしに参加者達がざわざわしている雰囲気が伝わってくる。

そして、各部屋に移動。Div2のとある部屋に振り分けられた。
午前1時開始なのだが、Arenaで、問題の選択が出来るようになっている。
「このメニューもう触っていいの??時間まで、触らない方がいいのなか?」とかと動揺しつつ、大人しくじっと待つ。

午前1時!!!
問題を開いてみる。Div2Easy、250点問題だ!

一見して、問題文がやたら短い!!
短い英文は、英語が不得意だと逆に分かり辛く、正確な意味がわからなかった。
が、しかし、Test casesをみる事でなんなく把握できた。

コーディングしてコンパイルすると、一発でコンパイル完了。
実行してみると、全部のテストケースをパス!!すぐさま、サブミット。

開始からたぶん15分くらいしか経っていなかった。
「何か奇跡がおこっている!!」
そう思って、今まで練習でも一回しか挑戦したことのない500点問題、div2Mediumを開いた。

問題文の英語はなんとなく理解できた。
さっそくプログラムを書き始めたが、使われている変数の型が「long long」とかなっているのが気になる。

私のプログラム技術はforもしくはwhileで単純に調べて回る全探索しか使えないので、あまり扱う数が大きくなると、単純にプログラムの時間が掛かりすぎて、制限時間オーバーになる可能性が高いという認識があった。

だから、long longみたいに「大きな数」を扱うのはヤバそうだったが、どうしょうもない。

とりあえず、プログラムが書けたのでローカルでコンパイル、そして実行。
案の定、実行時間が2秒を超えるテストケースがあった。つまり、時間オーバーだ。

しかし、どこかのページで「TopCoderのサーバーは、自分達が使っているパソコンより性能が高く早い、、」というのを見たのを思い出し、とりあえず、サーバー側でコンパイルしてテスト。

すると1.6秒くらいで実行できており、制限にかからないようだった。
そこで、「改善する方法探すより、次に行こう!!」ってことで、そのままサブミット。

なんと、未知の1000点問題Div2Hardに辿り着いてしまった。
多分、残り時間30分くらい。

勇敢に開いてはみたものの、問題文が何を言ってるかさっぱりわからない。
何度も読み返しているうちに、いわゆる「木構造」とかいうものの話なのかな?とか、edgeって点を繋ぐ線のことかな?とか、それくらいまで想像しつつ、、疲れて飽きてきた。

多分、これは問題が読み解けたところで、コーディングは全く無理と判断して、のんびり、問題文の意味を考え続けていたら制限時間が近づいてきた。
そこで、とりあえず、Greedが生成した空のソースをサブミットしておいた。

で、制限時間到来!!
5分の休憩時間。

この時、(その部屋の?)順位みたいなのが発表されていた。
ちらっと見たら、私のハンドル名がリストの上から2番目にあったような気がしていた。

暫くして、TopCoderに特有のチャレンジフェーズという、他人のソースを見てバグを発見し、ポイントをゲットする競争が始まった。そして、チャレンジフェーズが始まってみると、一覧のさっきの場所に、私の名前がなくなっていて「ん???」と思った。

私のHardの問題がチャレンジされて撃墜されていたのだ。
つまりは、Hardまでサブミットしていたので、その時点で点数が入っていて、上位に名前があったらしい。

しかし、あっという間の撃墜だった。まぁ、慣れてる人が見て、「こいつ、なめすぎ!!糞ニュービー」っていって、落とされたに違いないwww

チャレンジフェーズは、私も他人のソースをあれこれと眺めみるが、いまいち把握できない。この辺はきっと訓練が必要だ。

で、チャレンジフェーズが終わったら、システムテストが始まって、システム自体がサブミットしたソースを検証してくれる。これにパスすればポイントが確定してレーティングが計算されるみたい。

参加者の結果一覧をみていると、次々とシステムテストに通ったとか通らないとかの表示が出てくる。私の分もチェックされたらしく、何かのウインドがポップアップしていた。あまりよく読んでいなかったけれど、部屋を入りなおすとレイティングが更新されてるよみたいなことが書いてあったんだと思う。
チャット参加者の一覧から人がどんどん抜けていくので、私も追随。

入りなおしてみると、、、、
私のハンドルネームがブルーに!!!!

なんと、「ザクとは違うのだよ、ザクとは」だったのだ。


2014年10月3日金曜日

xmonadとHaskell(その16:レイアウトのスクリーンショット)

拡張モジュールにあるレイアウトモジュールは凄く沢山あるが、幾つかの視点から整理してみる。


基本的レイアウト

単独でレイアウトになれる型のデータを含むモジュール。
重なりか、非表示かがわかりやすい様にターミナルを透明にしてスクリーンショットを取ってみた。

工夫次第で使えそうな勧めレイアウト


XMonad.Layout.OneBig
一つだけ大きく



XMonad.Layout.TwoPane
XMonad.Layout.DragPane
画面を二分割で固定。マスターとそれ以外の2ウインドウ制。それ以外は非表示。
DragPaneの方が縦、横の選択等のカスタマイズができる。



XMonad.Layout.GridVariants
GridVariantsモジュールでは、Tallのメイン部分を任意の固定行x列にした上で、サブ部分がグリッド配置になるようにできたりする。



XMonad.Layout.ThreeColumns
メイン1行、サブ2行の固定



XMonad.Layout.MultiColumns
メイン1行、サブ行どんどん増えるが各行のウインド個数を指定できる



XMonad.Layout.Simplest
メイン1画面固定。
サブは非表示ではなく、メインの後ろに表示されている点でFullと異なる。



XMonad.Layout.StackTile
stacktileはdishesに似ているがメイン部分の高さが固定、サブ部分が増えるとサブの高さが小さくなる。



Tall改良版

hintを重視(文字がちゃんと表示される高さとか)

XMonad.Layout.FixedColumn
大きさ等指定を割合じゃなく文字数で

XMonad.Layout.ResizableTile
サブ側の高さがリサイズ出来る


その他のレイアウト

XMonad.Layout.Accordion
複数ウインドを開くとフォーカスのあるもの以外帯状に縮んだ状態になる。



XMonad.Layout.Circle
マスタが真ん中に、サブはその後ろで円状に配置



XMonad.Layout.Cross
マスタが真ん中に、サブはその後ろで十字形状に配置



XMonad.Layout.Roledex
斜めに綺麗に並べられる



XMonad.Layout.Spiral
渦巻き状にタイリング



XMonad.Layout.Mosaic
XMonad.Layout.MosaicAlt
各ウインドウの面積がある一定の法則になってる?


XMonad.Layout.Column
隣接ウインドウとの高さの比を規定



XMonad.Layout.Grid
XMonad.Layout.HintedGrid
Grid系は規則正しく格子状になるように配置をする。



XMonad.Layout.Dishes
メインの下にサブがお皿の用に積み重なっていく。



デコレーション系

xmonadでもタイトルバー的なものを付けることも出来るし、マウスによるボタンクリックによるウインドウ操作も可能にできる。

XMonad.Layout.DecorationAddons
XMonad.Layout.ButtonDecoration
XMonad.Layout.ImageButtonDecoration
各ウインドにバーを付ける



XMonad.Layout.TabBarDecoration
レイアウトにタブを追加する



XMonad.Layout.DwmStyle
各ウインドにDwmスタイルのタグを付ける



XMonad.Layout.DecorationMadness
幾つかのレイアウト(circle,accordion,tall)に飾りを付けたものを提供してくれる


XMonad.Layout.Decoration
テーマやシュリンカをカスタマイズする時のデフォルト値とか


    TopCoder

    本屋さんで「最強最速アルゴリズマー養成講座」という本を買ってみた。

    別に「アルゴリズマー」になろうとしたわけではなく、世の中には「プログラムコンテスト」なるものがあって、その筆者曰く、初心者こそ参加すべきという文言に目が留まったからだ。

    しかし、それよりもなによりも、そのコンテストは「TopCoder」といわれるものなのだが、このコンテストの優秀者(トップ0.2%)達は「RedCoder」と呼ばれ、これまた筆者曰く「『"赤いヤツは3倍早い"』というのはアニメだけの話ではありません。Redcoderは、素早くしかし華麗なコードを書き上げ、Challenge phaseでは容赦なく他人を撃墜していく存在であり、参戦者からすると恐怖の対象でもあります。」とかいう文句に心躍らされてしまった。

    昭和世代のおっさんは、アルゴリズマーであろうがなかろうが、少なくとも皆「ガンダマー」

    なので、参加しないわけには行きません。
    そう、「ザクだからって、なめるな!」なのです。


    http://www.topcoder.com/


    先の本が書かれたころよりも、ページが進化しているらしい。
    とりあえず、「Arena」に行くためには、ページ上段に並ぶ「challenges」からドロップダウンされるメニューの一番下「Topcoder arena」をクリック。

    ContestAppletProd.jnlpとかいうファイルがダウンロードされる。

    さて、windozeの場合、JREがインストールされていれば、このファイルをダブルクリックするなりでArenaが起動するが、archlinuxの場合は、すんなりいかないこともあるので、幾つか確認。


    1. icedtea-webパッケージのインストール
    *.jnlpというのは、JavaのJava Web Startという仕組みを使うらしく、そのために必要なパッケージが「icedtea-web」らしい。

    http://d.hatena.ne.jp/pogin/20120331/1333222488

    そのページを参考に

    #pacman -S icedtea-web

    で、インストール。

    そして、ダウンロードしたContestAppletProd.jnlpを以下のように実行。

    $javaws ContestAppletProd.jnlp

    セキュリティーの確認画面がいくつか出て、了解していけばArenaが立ち上がる。


    2.xmonadとjavaアプレットのFAQ

    xmonad上で、javaのアプレット扱う時にはFAQがある。
    何も設定しないと、アプレットに何も表示されない状態になって、びっくりしてしまうので、以下のページを参考に設定しておくのを忘れずに。

    http://qiita.com/xorphitus/items/efcca6652558bc5cc785


    #include XMonad.Hooks.SetWMName
    defaultConfig {startupHook = setWMName "LG3D"}

    みたいにstartupHookを設定しとけばOK(インクルード忘れずに)





    2014年2月3日月曜日

    xmonadとシステムトレイ

    うちのxmonadのステータスバーはdzenであり、システムトレイ的なものがない。

    スマホで撮った写真を簡単にパソコンで見るために、Dropboxを使ってみたんだけれど、「システムトレイアイコンからうんぬんかんぬん」という説明があったので、なんとなくつけてみたくなった。


    その前に、dropboxだ。

    Dropbox

    データ共有のアレ。
    https://www.dropbox.com/

    Archlinuxでは、AURにパッケージがある。

    また、archlinuxのwikiは以下。
    https://wiki.archlinux.org/index.php/dropbox


    取り立ててメモする程のものはないけれど、一応メモ。

    wikiにある通り、dropboxの使い方には「dropboxd」コマンドをxsession等から実行する使い方と、systemdでサービス(デーモン)として呼び出す使い方の2種類があるらしい。

    下準備


    どちらの使い方をするにしても、初期設定等についてあまり深く考えずに導入するためには以下の方法が良さげ。

    1.アカウントは事前にWeb等から取得しておく。
    2.yaourt等でdropboxのパッケージをインストールしたら、Xのターミナルエミュレータ上で、dropboxdコマンドを実行。ポップアップされる指示に従ってログインして、チュートリアルを最後までみる。

    以上で、ホームディレクトリに必要なファイル等が用意されるはず。
    あとは、適当にターミナル上でC-cとかして終了させる。

    xmonadでタスクトレイがない場合、タスクトレイアイコンからの設定が出来ないので、別途dropbox-cliパッケージ(AUR)をインストールして操作するべきかもしれない。が、うちではほったらかし。
    というか、さっき試しにインストールしようとしたら、チェックサムが合わない(?)とかいうエラーでインストール出来なかった。そのうち、覚えてたら再度試してみようかな。

    systemdから


    上記のタスクトレイアイコンからの設定では「自動起動」の項目なんかがある、DEやopenboxなんかのWMの場合は、その効果が反映されそうだが、xmonadを使ってる限りは関係なさそう。
    なので、systemdのサービスとして使う。

    systemdを使った場合、システムが動いていればアカウントにログインしていようがいまいが、ディレクトリの同期をしてくれるっぽい。一方、Xの起動を前提としていないので、タスクトレイのアイコンが出てこない。

    が、wikiにある通り、次の設定をすればシステムトレイアイコンがでてくる。

    さて、この設定の仕方なんだけどwikiでは
    「/etc/systemd/system/dropbox@.service」のファイルに

    .include /usr/lib/systemd/system/dropbox@.service
    [Service]
    Environment=DISPLAY=:0

    という内容を書くといいとなっている。
    設定の内容は、元の設定に環境変数の設定(X上に表示を行う)を追加しているものだ。

    systemdでは、この「/etc/systemd/system/」ディレクトリ以下に「ファイル」を作成すると「/usr/lib/systemd/system/」ディレクトリ以下の同名の設定ファイルの内容が上書き設定される仕組みになっている。

    しかし、今回の場合は、一部の追加であり、そのため、わざわざ、元ファイルを読み込んでいる。

    この様な時には、追加設定の方法をとる方が格好良さそう。
    その方法は、「/etc/systemd/system/」ディレクトリ以下に「設定ファイル名.d」というディレクトリを作る。上の場合なら「/etc/systemd/system/dropbox@.service.d/」というディレクトリだ。そして、次にそのディレクトリの中に「hoge.conf」というファイルを作りそこに追加したい内容を記述すればよい。

    さて、実際には、dropboxのサービスファイル名はユーザー名が入って構成される。うちの場合「neko」というユーザーなので

    # systemctl enable dropbox@neko.service

    であり、システムトレイアイコンのためには

    #mkdir /etc/system/systemd/dropbox@neko.service.d

    としてディレクトリを作成した上で、

    #vim /etc/system/systemd/dropbox@neko.service.d/env.conf

    とかして

    [Service]
    Environment=DISPLAY=:0

    とだけ、env.confファイルに記述すればよい。

    https://wiki.archlinux.org/index.php/systemd


    stalonetray


    本題の、xmonadでシステムトレイだが特に難しいことはなにもない。
    「stalonetray」という単独のシステムトレイアプリがある。

    うちのdzenは、ご存知の通り「つぎはぎ」されている。
    そして、システムトレイもこれと同様にstalonetrayを「つぎはぐ」のだ!


    本家
    http://stalonetray.sourceforge.net/manpage.html

    Archのwiki
    https://wiki.archlinux.org/index.php/Stalonetray


    とりあえず、実行しておけば、そこにシステムトレイアイコンが表示される。

    dzenとうまく「つぎはぎ」するコツは以下の2点だ。

    背景色を同じにする

    dzenの背景色と同じにすることで、一体感をだす。
    -bg "#000000"


    高さを合わせる


    dzenと高さを合わせる。
    dzenは「-h」オプションでピクセル単位の高さを指定している。

    一方、stalonetray側の高さの指定は「--geometry 」オプションで行い、その引数の書式は

    widthxheight[+x[+y]]
    となっていて、例示すれば「1x1+0-0」という感じだ。
    ここで、注意すべきはwidthもheightも単位はアイコン何個分か?である。つまり、ピクセルではない。

    では、アイコン1個の大きさはどうやって決まるか?
    「--slot-size」オプションにピクセル数を指定して使う。

    dzenの高さが20なら、「--slot-size 20」として、--geometryのheightは1にしておけば良い。

    「--slot-size」の指定は横幅も同じ数値になるので、widthの調整もこの数字に着目して計算すれば良い。

    あとは、適当でも良さげ。
    stalonetrayのオプションの指定は、コマンドラインに並べても、設定ファイル(デフォルトでは~/.stalonetrayrc)を読み込んでもどっちでもいける。

    xmonad.hsの中で呼び出した場合には、コマンドラインに並べたオプションにして、dzenとの関係から、長さを計算で出した方がスマートっぽいかも。

    上手につぎはぎ出来ました

    と思って晒してみたけど、特にスマートっぽくもないか。

    まぁ、システムトレイアイコンがあると見た目が今時っぽくなった。





    2013年12月31日火曜日

    vimとhaskell

    自己紹介の処にも書いてある通り、普段はemacs派。
    linux使い始めた頃がJE時代のMuleだったので、それしか知らなかったってのも大きな要素。

    初心者の頃、root作業中に意思に反して立ち上がるviは恐怖以外のなにものでもなく、エスケープ連打と:qだけはマスターしてた。

    ところが、なんかのきっかけでvimというのを触ってみたら、インサートモードでもバックスペースで文字が消せ、しかも、カーソルキーでカーソルが動く!!そんな普通のエディタっぽくなってたので、ドットインストールとかvimtutorとかして、最近では、とりあえず触るくらいはできるようになった。

    で、emacsでは、各プログラム言語に対応した「なんとかモード」的なものがあるのだけれど、vimってどうなってるの?という初心者的疑問から、ちょっとだけ環境整備できたので、そのメモ。


    設定ファイルvimrc

    個人の設定ファイルの場所は7.4以降(archlinuxでのパッケージは7.4)

    ~/.vim/vimrc

    vimは、「vim script」と云うもので、制御できるらしい。
    以下のページのスライドにざっと目を通すと雰囲気が確認できた。
    http://www.slideshare.net/cohama/vim-script-vimrc-nagoyavim-1

    とりあえずは




    プラグインのための準備


    vimの機能拡張の管理をするための仕組みとして「neobundle」というのを使う。

    https://github.com/Shougo/neobundle.vim

    の「Quick start」の項目をみて、準備をする。

    まず、~/.vim/bundle/ディレクトリを作成して、その中にgithubからneobundle.vimをコピー

    次に、~/.vim/vimrcにneobundleのための必要事項を記入。(例をコピペでOK)

    これで準備完了!!

    プラグインのインストール


    プラグインというものをインストールしてみる。
    まずは、ステータスバーをカッコよく!!

    https://github.com/itchyny/lightline.vim

    スクリーンショット見ただけで、ワクワク。

    「Installation」の項目をみると幾つかの方法が示されている。
    うちは「neobundle」という方法を使うので、「neobandle」の方法を見てみると

    NeoBundle 'itchyny/lightline.vim'


    とかかれている。

    この一行を、~/.vim/vimrcにコピペする。
    コピペの場所は

    NeoBundleFetch 'Shougo/neobundle.vim'


    の下辺りに書けばよい。



    haskellの環境


    vimでhaskellする人たちのページによく紹介されているものに「ghcmod-vim」という、haskellコードの中の型の表示やコードのチェックをしてくれる便利なプラグインがある。

    https://github.com/eagletmt/ghcmod-vim

    で、このプラグインは、「ghc-mod」という外部プログラムを使うので、それを先にインストールしてねと説明される。そして、そのインストールは、「cabal」というのを使ってインストールできますよと説明される。「cabal」っていうのは、haskellプログラムのパッケージマネージャのようなもので、pacmanみたいなものらしい。

    そこで、注意が必要なのだ!
    archlinuxでは、pacmanというパッケージのシステムがあるが、それを介さずにシステムに何かをインストールする時は、その部分について自分で管理しなければならない。

    以前railsとかを使うときに、rubyでも同じようなことがあった。何かのコミュニティが独自のパッケージシステムを持っているときに、ディストリビューションのパッケージシステムとどう折り合うかは面倒くさい問題だ。

    というわけで、haskellについてのarchlinuxのwikiをみてみた。
    https://wiki.archlinux.org/index.php/Haskell_Package_Guidelines

    すると、パッケージング云々の前に、archlinuxでのhaskellの環境について知っておくべき重要なことが書いてあった。

    archlinxとhaskell


    まずは、リポジトリについて。
    Archlinuxとhaskellの関わり方の方法は2つの選択肢があるらしいということを知った。

    ひとつは、archlinuxのリポジトリにあるhaskellに関するパッケージを使うという選択肢。

    もうひとつは、最新のhaskellパッケージを取り入れてある、ArchHaskellプロジェクトのリポジトリを使うという選択肢だ。

    とりあえずは、archlinuxのリポジトリで満足。

    次に、「Haskell-Platform」というものについて。
    システム上でhaskellを使う場合、通常は「Haskell-Platform」と呼ばれるひとまとまりの環境をインストールするらしい。ところが、archlinuxのパッケージングでは、これらは以下の5パッケージに細分されている。

    ghc
    cabal-install
    haddock
    happy
    alex
    特に、xmonadをインストールする時に依存で勝手にghc等がインストールされた場合には、他のものがインストールされていなかったりするので、超要確認だ

    というわけで、archlinuxでcabal installするなら、まずは

    pacman -S ghc cabal-install haddock happy alex

    しろってこと。

    cabalでghc-modをインストール

    さて、cabalによるhaskellパッケージのインストールはデフォルトでユーザー領域、~/.cabal以下にインストールされる。なので、当初の心配事であったシステムとの整合性はあまり問題ないとおもう。

    まず、cabalを使う下準備は、シェルから「cabal update」すると、はじめてのときは、~/.cabalディレクトリを作って、必要なことをやってくれる。あと、cabal自体の最新版があるからアップデートしてね的なメッセージは無視。cabal-installパッケージ自体はpacmanの方に任せることにする。

    その作業が終わったら、パッケージをインストールしてみる。ターゲットはghc-modだ。

    cabal install ghc-mod

    依存関係にある他のパッケージとかも一緒にインストールしてくれる。
    haskellのコンパイルはs101にとっては重労働らしく、結構な時間がかかるが、辛抱強く待てばそのうち終わる。

    実は、、


    実は、うちでは結構ハマったので、他にも陥っている人がいた時用のメモ。

    haskell-platformというものを知らなかったので、適当にcabal-installパッケージをpacmanでインストール。そして、「cabal install ghc-mod」すると、インストール途中で何かのファイル(モジュール)が足りないということで、エラー。
    これが、事の発端だと思う。

    そこから、あまりエラーメッセージを読まずに、上で書いたarchlinuxのwikiを見て、リポジトリ変えたり、足りないパッケージ入れたりして、試してた。その中で、cabalインストールを初期化した方が良いだろうと思って、.cabalディレクトリを消したりしてた。

    で、どうもうまくいかない。そして、エラーメッセージをよく見ると、ありそうなはずのモジュールがないといっている。。。

    で、いろいろやってて見つけたのが~/.ghcの中のパッケージデータベース。
    ~/.cabalを直接消したりしてたから、これとの整合性がとれなくなってたらしい。

    なので、はじめてcabalする時にごちゃごちゃやって、上手くいかなくなってるなら、~/.cabalと~/.ghcを両方削除して、一からやり直してみると良いかも?


    お勧め?


    とりあえず、この辺を順番に試してみようかなぁ

    VimでHaskellを書く時に入れておきたいプラグイン5つ

    すごい Vim で Haskell を書こう ... の補足

    四苦八苦して入れたghc-modを使うghcmod-vimは、s101だと、結構重かったりした。
    まだ、全部は試してないけれど、記念撮影♪




    2013年12月28日土曜日

    xmonadとHaskell(その15:レイアウト設定)

    (その14)からの続きで、xmonad関数の型クラス制約に戻ってみる。

    xmonad :: (LayoutClass l Window, Read (l Window)) => XConfig l -> IO ()

    前回見た単純な形の型クラス制約と比較すると、ちょっと複雑な形なので解きほぐそう。
    まずは、カンマで区切ってカッコで包まれいる書式は、複数の型クラス制約をあらわしていて、

    LayoutClass l Window



    Read (l Windw)

    に分解することができる。

    そこで、LayoutClassに付いてのみに着目してみると

    xmonad :: LayoutClass l Window => XConfig l -> IO ()

    のような形に書けるのだが、これも前回の単純なメソッドの型クラス制約と違うところがある。何が違うかといえば、型クラス制約の型の形である「l Window」と、引数「XConfig l」が一致していない。

    これは、XConfig l型データそのものが、LayoutClass型クラスにあるメソッドの引数になるものではないからである。

    メソッドの引数になるのは、XConfig l型データに内包される「l Window」型の値、すなわち、layoutHookフィールドの値だ。つまり、xmonad関数は、レイアウト操作をする時に、この値を引数にして内部的にLayoutClass型クラスのメソッドを呼び出すのだろう。

    というわけで、結論から言えば、layoutHookフィールドに定義するものが、LayoutClass型クラス(及び、Read型クラス)のインスタンスの値であれば良いということだ。

    さてさて、LayoutClass型クラスというのは、どんなもので、どんなメソッドがあるのか気になる場合には以下のリファレンスが参考になる。
    http://xmonad.org/xmonad-docs/xmonad/XMonad-Core.html#t:LayoutClass

    しかし、それらメソッドは上で話した通り、xmonad自身が内部的に呼び出すだけなので、レイアウトに関する型を自作してインスタンスとしての実装をするのでない限りは、そういうメソッドがあるという知識を持つレベルで十分ぽい。

    というわけで、「型クラス」というものがあるという知識を得た上で、あらためてレイアウトの設定に臨んでみる。

    さっそく、XMonad.Layoutモジュールのリファレンスへ!
    http://xmonad.org/xmonad-docs/xmonad/XMonad-Layout.html

    layoutHookに定義するのはLayoutClassのインスタンである型の値ということがわかったが、具体的になんの型がLayoutClassのインスタンスなのかどうやって調べるのだろう??

    実は非常に簡単!!
    リファレンスの「型」の項目には、ちゃんと「インスタンス(instances)」という項目があったりするのだ。

    Full a型なら、以下のような記述が見つかる。

    LayoutClass Full a
    Read (Full a)
    Show (Full a)

    これは、LayoutClass、Read、Showの型クラスのインスタンスだという記述なのだ。


    レイアウト設定の基本


    さて、型クラスのはなしはこれくらいにして、次は、xmonad.hs上で実際にレイアウト設定を行う上で知っておくべき更なる実践的な知識を把握しよう。

    単独基本形


    単独で、LayoutClass型クラスのインスタンスとなっている型は、大雑把に言えば、「基本的なレイアウト」を表している。例えば、「Full a型」や、「Tall a型」であり、これらの型の値は、それ単独で1つのレイアウト設定を行えるのだ。

    だから、Full a型を単独でlayoutHookフィールドに設定するのが、レイアウト設定のもっとも基本的な設定になる。

    layoutHook = Full


    レイアウトの連結


    デフォルトのレイアウト設定でお馴染みのように、レイアウトはm-spaceで切り替えることが可能だ。その仕組みがレイアウトの連結だ。

    これは、個々に独立したレイアウト設定であるLayoutClass型クラスのインスタンスの値を(|||)演算子で繋ぐだけである。

    layoutHook = Full ||| Tall 1 (1/100) (1/2)


    メッセージ


    さて、連結されたレイアウトは、m-spaceで切り替える事ができるのだが、それは何故なのか??

    実は、レイアウトの設定に働きかける「メッセージ」という仕組みが、そのキーにバインドされているのだ。defaultConfigでのm-spaceのキーバインドを覗いてみると

    ((modMask, xK_space ), sendMessage NextLayout)

    そして、sendMessage関数はXMonad.Operationsに定義がある。

    sendMessage :: Message a => a -> X ()


    ここにも型クラス制約が出てきた。すなわち、Message型クラスのインスタンスを引数に取るのだ。

    で、実際にsendMessage関数の引数に渡されている「NextLayout」は、大文字アルファベットなので、値コンストラクタである。

    そして、このNextLayoutもXMonad.Layoutのリファレンスに見つけられる。

    「ChangeLayout型」の項目をみてみよう。
    そこに、値コンストラクタとしてNextLayoutが見つかり、その他にFirstLayoutがあるのがわかる。また、インスタンス項目には「Message ChangeLayout」と書かれており、Message型クラスのインスタンスであることが確認できる。

    というわけで、xmonadでは、このsendMessage関数とMessage型クラスのインスタンスを使ってレイアウト設定を操作することができるのだ。

    すなわち、(|||)演算子を使ってレイアウトを結合している時には、このメッセージをつかってレイアウトの切り替えができる。

    XMonad.Layoutモジュールにある他のメッセージもついでに見てみよう。

    「Resize型」は、マスターペインの大きさを変化させる。
    値コンストラクタはShrinkとExpand。

    Tallレイアウト等の時、m-lやm-hで変化出来るアレだ。
    defaultConfigソースを見れば

    , ((modMask, xK_h ), sendMessage Shrink)
    , ((modMask, xK_l ), sendMessage Expand)


    となっている。

    もう一つ「IncMasterN型」は、マスターペイン側に入れるウインドウの数を変化させる。
    デフォルトでは、Tallレイアウトのメイン(左側)は、ウインドウが1つだが、この数を増やしたり減らしたりできる。
    値コンストラクタは一つの引数Intをとる。増やしたり減らしたりする数の指定だ。
    で、またdefaultConfigのソースを見れば

    , ((modMask, xK_comma ), sendMessage (IncMasterN 1))
    , ((modMask, xK_period), sendMessage (IncMasterN (-1)))


    となっている。

    このResize型やIncMasterN型のメッセージはTallレイアウトにだけ効果があるわけでなく、同じような構造のレイアウトには同じように効果がある場合もある。

    また、それぞれのレイアウトについては、独自の操作用メッセージがセットになっていたりするので、モジュールの中にMessage型クラスのインスタンスを見つけたら、何の操作をするためのものかを確認しよう!!

    ちょこっと修正系


    レイアウトの中には、自分自身が単独でレイアウトになるのではなくて、既存のレイアウトを変化させて新しいレイアウトを作るものがある。
    例えば、「Mirror l a型」だ。

    値コンストラクタの形は、

    Mirror (l a)

    となっており、インスタンスの形が

    LayoutClass l a => LayoutClass (Mirror l) a

    となっている。

    「(Mirror l) a」型がLayoutClass型クラスのインスタンスなのだ。
    つまり、LayoutClassのインスタンスをMirror値コンストラクタの引数に与えると、新たなLayoutClassのインスタンス、すなわち、レイアウトが生成される。

    このMirror l a型、具体的には、Mirror値コンストラクタに、ある既存のレイアウトを入れると、その既存のレイアウトを90度回転した新しいレイアウトを生成してくれる。

    さて、このMirror l a型のような役割を果たしてくれるものの仲間にLayoutModifierと呼ばれるものがある。
    以前(その10)でメモした、ステータスバーの部分にウインドウが重ならないようにlayoutHookに設定したavoidStruts関数がこれにあたる。

    XMonad.Hooks.manageDockモジュールのリファレンス
    http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Hooks-ManageDocks.html


    avoidStruts :: LayoutClass l a =>
    l a -> ModifiedLayout AvoidStruts l a


    つまりは、LayoutCLassのインスタンスを引数にして渡すと、ModifiedLayoutなんたら型が帰ってくる。

    この「ModifiedLayoutなんたら型」は、XMonad.Layout.LayoutModifierモジュールで規定されているのだが、重要なのは、コレ!

    (LayoutModifier m a, LayoutClass l a) =>
    LayoutClass (ModifiedLayout m l) a


    つまりは、LayoutModifier型クラスのインスタンスを用いて修正された、「(ModifiedLayout m l) a」型はLayoutClassのインスタンス、すなわち、レイアウトになるってことだ。

    具体的な使い方のパターンは、avoidStrutsのように、修正用関数にレイアウトを引数として渡すと、新しいレイアウトが返るパターンだ。

    LayoutModifierの例をもう一つ。
    http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Layout-Spacing.html

    実は、以前使っていたawesomeからxmonadに乗り換えたきっかけが、このspacing機能だ。

    before

    layoutHook = spacing 2 $ Tall 1 0.03 0.5

    after

    わかる??? このウインドウの周辺のクールな隙間!!

    smartSpacingなら、ウインドがひとつのときには隙間を作らないという、ちょっとだけかしこな感じを出してくれる。

    さて、このクールな隙間!!
    http://www.youtube.com/watch?v=4mMb7qXwhuU
    の人もawesomeからxmonadへ(隙間がやりたいこととは限らないけれど、そうじゃないともいいきれない)
    某掲示版でも、この隙間は話題になってて、みんな、「お前は俺か」なのだ。
    そう、xmonadを使う理由は、haskellがどうだとか、xineramaがどうだとか言ってるけど、「ほんとはお前ら単に隙間がかっこいいと思っただけなんじゃね?」と密かに思ってたりする。


    さて、話は変わって、実は、(|||)演算子の結合結果も、ある意味このレイアウト修正系の種類の一つであると考える事も出来る。(|||)関数は、もともとのレイアウトに、他のレイアウトも選択できる機能を追加した新しいレイアウトを生み出しているのだ。


    (|||) :: (LayoutClass l a, LayoutClass r a) =>
    l a -> r a -> Choose l r a


    このChoose l r a型はも、LayoutClassのインスタンスだ

    (LayoutClass l a, LayoutClass r a) => LayoutClass (Choose l r) a


    ちなみに、(Mirror l)や(Choose l r)、(ModifiedLayout m l)は(その13)でみた例の型コンストラクタと部分適用のアレだ。

    というわけで、(|||)演算子の戻り値は、ひとつのLayoutClass型クラスのインスタンスなのだ。

    これは、何を表しているかというと、「ひとまとまり」であるということも表しているのだ。

    なので、次のような書き方は

    layoutHook = avoidStruts (Full ||| Tall 1 (1/100) (1/2))

    当然、FullにもTallにもavoidStrutsの効果が及ぶ。
    これは、カッコで括っているからではなくて、FullとTallの結合した一個のレイアウトに対してavoidStrutsしてるイメージだ。

    avoidStrutsの効果を個別に及ぼさせるには、結合させる前にもとのレイアウトを直接変化させればよい。

    LayoutHook = Full ||| avoidStruts (Tall 1 (1/100) (1/2))