yunomuのブログ

趣味のこと

スタイラスペンとブギーボードの話

iPad用に静電気タイプのスタイラスペンを買って使ってみてますけど、ここまで書いた段階でもういいやって感じです。参ったな高かったのに。
http://www.princeton.co.jp/product/digitalaudio/psatpa1.html

電源入れないと書けないので電池を気にしなきゃいけないのが一番のネックかなぁと思っていましたけど、その点はまあそんなに使うわけじゃないし、単6電池1本で140時間連続で使えるとのことなのであんまし問題は無いかもしれません。ただ文字の書き心地が著しく悪いので私には使えませんでした。
ペンの形状はいいのでもったいない感じはあるんですが、たぶんその形がいいのと感度が良すぎるのが災いして、文字が書けない。

前に買ったBambooのスタイラスペン(http://www.wacom.com/jp/ja/everyday/bamboo-stylus-solo)と比べると、長いしペン先が細いしでとても持ちやすいんですが、それゆえについ少しペンを寝かせてしまうので、接地の位置が思ったよりかなり手前にきてしまうという。普通のペンならペン先の頂点あたりからインクが出ますけど、ペン先の根本の部分からインクが出る感じになってしまって、それで字が書けるわけがない。いや、私がペンを寝せて書く癖があるからなので、もしかしたらシャーペンやボールペンを普段使う人は大丈夫なのかもしれませんけど。

Bambooのやつはペン先が太いので逆にそんなことはなく、快適に書けるんですが。
何事も吊り合いとかバランスとか適材適所とか、そういう感じですね。

ところで最近は家電量販店の文具コーナーに結構面白いものが色々ありますね。
というかキングジムが面白いですね。

ブギーボードというやつ。
http://www.kingjim.co.jp/sp/boogieboard/
電子メモのようなもので、適当な棒とか爪とかで引っ掻くと書ける。書いた線はeraceボタンで全消しできる。部分的には消せない。電池交換はできないけど、内部電池が切れるまで5万回程度書けるらしい。
「アイデアメモに!」って書いてあったけど、この仕様だとアイデアメモには使いづらいんじゃないかなぁと思います。
ああでも私が見たのは型番BB-1Nという一番小さくて単機能なやつだったんですが、上位モデルになると保存とかUSBでのデータ転送とか充電とかできるんですね。それならメモとして使えそうですね。

大きさはiPad miniと同じくらい。用途は人に見せるための連絡用ボードみたいな感じでしょうか。「冷凍庫にカレーが入ってます」みたいなの。
ペンが自由なのがいいですね。消しゴムが無いというのも、このサイズならあまり問題にならないんじゃないでしょうか。もう少し大きかったら複数の情報を書くようになるから全消しのコストが高くなる。そうすると部分的に消せる消しゴム機能がほしくなって、全体的になんか使いづらいアイテムになると思う。
少し大きくて消しゴム機能があったらプレゼンテーションの道具になりますね。ホワイトボードでいいじゃん。
バランス大事ですね。

なので私が使うとしたら、やっぱり伝言メモにする感じですかね。この場合は、電池交換できない書き換え5万回というのも特に問題にならないし、3千〜4千円くらいの値段もまあまあまずまずといったところなんじゃないでしょうか。
まあ私が実際に使う場面は無さそうなんですけどね。
こういうの想像するのが楽しいんじゃないですか。

JavaコードをHaskellで書きなおすのに手こずった話

「続・アルゴリズムを学ぼう」が発売されて、校正をほんのちょっと手伝ったお礼かなんかで発売された本を頂きまして、ぼちぼち読んだりしています。
前作に比べて使いやすいというか、親しみやすいネタが多くて面白いですね。
「続・アルゴリズムを学ぼう」http://www.amazon.co.jp/dp/4048913948/

で、ちょっと暇つぶしに「続・アルゴリズムを学ぼう」に載ってるリバーシHaskellで実装してみました。
https://github.com/yunomu/exercises/tree/master/reversi

この本に載っているプログラム例はJavaで書かれているので、要はJavaHaskellで書きなおすという作業をしたような感じになりました。

前になんか勘違いしていた話

JavaHaskellといえば、前に社内で"Types and Programming Languages"の読書会をやろうって話になった時にこんな事を言っている。

ここで言う型クラスというのはHaskellの型クラスのことで、見た目は割と似ていますよね。似てるんじゃないかな。
例えばEqとか、

class Eq a where
    (==) :: a -> a -> Bool
    (/=) :: a -> a -> Bool

ってなってて、いかにもインタフェースを定義している感じ。こういう振る舞いをするデータを作りたかったら、データ型を作ってこの型クラスのインスタンスにすればいいんじゃないかなと思う。
まあやってみると全然違うんですが。

Javaのinterfaceは型だけども、Haskellの型クラスは型ではないので、Javaのinterfaceみたいなノリで型クラスを使うと、徐々に無理が出てきて後悔することになる。

class ToInt a where
    toInt :: a -> Int

instance ToInt Int where
    toInt = id

instance ToInt Char where
    toInt = const (-1)

みたいな型クラスがあったとして

f :: ToInt a => [a] -> [Int]
f = map . toInt

a = f [2, 'a']

みたいなことはできない。リスト内の型が違うから。

b = [toInt 2, toInt 'a']

これはできる。まあ、そりゃできる。
こうしてみれば当たり前なんだけど、toInt関数の扱い方に気をつけなきゃいけないのでそれなりに面倒な場面が増えてくるというか、感覚的には「同じtoIntって関数が使えるんだから同じように扱えてもいいじゃん」って思うんだけど、シンボルというか名前が同じでもChar型のtoIntとInt型のtoIntは別物なので、別物として扱いましょう。
同じ型クラスならリストに入れられるようにしようみたいな話もどっかにあった気もしますが。

型クラスはやっぱりShowみたいに型によって処理を振り分けたい時に使うのが良さそうですね。
インタフェースが同じなら素直に同じ型にしましょう。

継承やコンストラクタやインタフェース定義

Haskellの型定義にはJavaの継承とかコンストラクタみたいなものはなくて、メソッドもなくて、どうするのこれってなります。
ならないなら幸せです。人やコードによってはならないんじゃないかな。
本ではプレイヤーをこんな風に定義してる。

public abstract class Player {
    protected final Turn turn;
    protected Player(Turn turn) {
        this.turn = turn;
    }
    public Turn getTurn() {
        return turn;
    }
    public abstract Position play(Board board);
}
public class HumanPlayer extends Player {
    ...
}

抽象クラスの`Player`を定義して、それを継承してHumanPlayerとかSimpleAIPlayerとかを作ってる。
これはそのままだとHaskellに変換できないんだけど、よく考えれば具象クラスが要らないだけだったりする。コンストラクタの代わりに初期化関数を作る。

data Player = Player
    { playerTurn :: Turn
    , playerPlay :: Board -> Player -> IO (Maybe Position, Player)
    }

initHumanPlayer :: Turn -> Player
initHumanPlayer t = Player t humanPlay

humanPlay :: Board -> Player -> IO (Maybe Position, Player)
humanPlay = ...

Java風に言うと、テンプレートメソッドパターンがストラテジーパターンになってる。というかJavaでもこう書けよという気がしてくる。抽象クラスがいいのかストラテジーがいいのかはここでは微妙なところかもしれないけど。

戻り値の型

Javaのplayメソッドのシグネチャはこうなってるけど

    public abstract Position play(Board board);

Haskellのplayの型はこうなってる。

playerPlay :: Board -> Player -> IO (Maybe Position, Player)

このインタフェースはちょっと悩んだんですけど、

  • Playerの内部状態を使うかもしれないから引数にPlayerが必要
  • Playerの内部状態を更新するかもしれないから戻り値にPlayerが必要
  • Positionが決まらない場合があるからMaybe Position(元プログラムではnullを返している)
  • ユーザの入力や乱数を利用して手を決めるかもしれないからIO

という感じで決めました。
SimpleAIPlayerだとIOが要らないし、HumanPlayerだとMaybeが要らないし、もっと後の方になるまで戻り値のPlayerが要らなかったりするので、ここは先見性が試されるというか、3回くらい書き直しました。

IOが必要かどうか、値が存在しない場合があるかどうか、このあたりを最初から慎重に設計してなきゃいけないけども、このあたりは結構難しいところだったと思います。機能追加の度に共通部分を書き直す羽目になりました。よく考えれば自明なんですけど、Javaのメソッドは基本的に副作用があるというのは忘れがちな気がします。

そんなこんなで、暇だからAI作って遊び相手になってもらおうと思って書き始めたものの、案外面倒くさくて、ここまで書き終わる頃には新幹線が目的地に着いてしまったという。それはそれで良い暇つぶしにはなりましたけど。

lens

しーんじてーこーころがとーきーめーいたー瞬間をー

遠い昔のことですが、こんな記事を書きました。
record update - yunomuのブログ
recordのupdateめんどくさいよねという話。

で、コメント欄でふみさんに「lensあるよ」って言われました。
http://hackage.haskell.org/package/lens
あるよっていうか、存在は知っていたけど、こういう用途に使うものだったんですね。デカい図が貼ってあるけど何言ってるかわかんねぇ。

とりあえず使ってみました。

{-# LANGUAGE TemplateHaskell #-}
module Main where

import Control.Lens
import Data.Text (Text)

data Music = Music
    { _title :: Text
    , _count :: Int
    }
  deriving (Show)
makeLenses ''Music

とりあえずこれで準備OK。lens使う時はレコードのフィールド名を'_'で始めないといけないっぽいです。
あとはmakeLensesのためのTemplateHaskell拡張。このとき、例えばこのMusicというデータの中で他のデータ型を参照している場合はこの部分より前でそのデータ型を定義しておく必要があるとか、titleとかcountとかいう関数が自動生成されるから注意するとか、TemplateHaskell的な制約が少々。
あとアンダースコアがそもそもダサいとか。その辺は、lensを使うとそもそも生のフィールド名を使わずに済みそうなので、割り切って見なかった方向で行くといいのかもしれない。

% ghci -XOverloadedStrings
...
[1 of 1] Compiling Main             ( Main.hs, interpreted )
Ok, modules loaded: Main.
*Main> let music = Music "純愛レンズ" 0
*Main> music
Music {_title = "\32020\24859\12524\12531\12474", _count = 0}

例題が微妙にマズかった。なんでTextで日本語にしたんだ。それはそうと、これだとレコードの更新はこんな風に書ける。

*Main> let a = Music "Mermaid festa vol.1" 0
*Main> a
Music {_title = "Mermaid festa vol.1", _count = 0}
*Main> a{_count = _count a + 1}
Music {_title = "Mermaid festa vol.1", _count = 1}
*Main> a&count %~ (+1)
Music {_title = "Mermaid festa vol.1", _count = 1}

従来と比較して、まあ正直どっちがいいんだかはよくわからないけども、少なくとも`a`とか`_count`が2回出てこないのは良い。

でもこの書き方のいいところは他のデータ構造と一緒に使った時で
例えばMapでadjustを使うとき

*Main> import Data.Map
*Main Data.Map> let m = insert 9 a empty
*Main Data.Map> m
fromList [(9,Music {_title = "Mermaid festa vol.1", _count = 0})]
*Main Data.Map> adjust (\v -> v{_count = _count v + 1}) 9 m
fromList [(9,Music {_title = "Mermaid festa vol.1", _count = 1})]
*Main Data.Map> adjust (&count %~ (+1)) 9 m
fromList [(9,Music {_title = "Mermaid festa vol.1", _count = 1})]

下の2つは同じ事をしているんだけど、要らないところが削れてだいぶ良い感じになったような気がする。構文というか、演算子が見やすいかどうかは意見が別れるところだろうけども。

という風に、Data.Map.adjustとかControl.Monad.State.modifyとかを多用する私みたいな人には割とおすすめなライブラリかもしれないです。
普通にgetterとかsetterっぽいのもあります。

*Main> a^.count
0
*Main> a^.title
"Mermaid festa vol.1"
*Main> a&title .~ "No brand girls"
Music {_title = "No brand girls", _count = 0}
*Main> a&title .~ "Love marginal" &count .~ 3
Music {_title = "Love marginal", _count = 3}

というか単に私がまだこの3つの操作しか覚えてないだけですが、もっといろんな使い方を知ると便利なライブラリになると思います。たぶん。

こんなかんじで更新を抽象化してる風な関数を定義したりとかもできますけど、

*Main> let upd rec field value = rec&field .~ value
*Main> upd a title "sweet & sweet memories"
Music {_title = "sweet & sweet memories", _count = 0}

[(FieldName, Value)]みたいな組のリストを渡して突っ込むみたいな事は、組のリストを作れない関係でできないので、作ってもあんまし意味が無い気がしますね。

でもこの3つの操作を覚えるだけでも結構気持ちよくやれる気がします。recordなんて要らんかったんや!

ソース
https://github.com/yunomu/exercises/blob/master/lens/Main.hs

手帳とノートと私

システム手帳というデバイスは、並列した大量の情報を処理するために機関銃が一般化して散兵戦が主になった頃の軍で生まれた、「つまりシステム手帳はミリタリーアイテムなんだよ!」って軍オタが言っていたのを聞いたことがありますが、本当かどうかは知りません。

私も何度かシステム手帳を持ってみようとしたことがあったんですが、あまり役に立った事はなく、それもそのはず処理しなけりゃいけない情報そのものがそんなに多くなかったし、幸い私は記憶力が良かった。両親をはじめご先祖様ありがとう。思えば身にかかる問題のほとんどを記憶力で解決してきた気がします。

まあそれはどうでもいいんですが、
ただシステム手帳が役に立ったことがなかったわけでもなくて、就職活動中なんかは役に立ちましたね。並列する時系列のイベント群の例として非常にわかりやすいんじゃないかと思います。テーマというか会社ごとにスケジュールやメモを並べて整理しつつ、移動中にも読み書きできる。まさにシステム手帳の本領発揮。
いやそういう事やった時は結局就職しなかったんですがね。実際に就職した時には並列して受けてないし、手帳はリストラしてスケジュール帳しか持ってなかった。いやスケジュール帳も持ってなかったかも。携帯とGoogleカレンダーがあったしねぇ。

あと手帳が活躍したのは就職後、会社勤めは大っぴらに遊ぶわけにはいかない状況(研修とか)が増えますので、その時の遊び道具として。熱心にメモを取ったりアイデアを練っていると見せかけて、今ここに書いているようなしょうもない文章を書いていたりする。してました。
授業中の暇つぶしといえばペンの分解と落書きが定番ですが、大人になったら万年筆の手入れとブログの記事作りになった。人間は変わらない部分もある。

この時に使っていたのはA6ノートで、理由は当時流行っていたからというか。3年くらい前、本屋のビジネス書とかのコーナーで「100円ノートの活用法」とか「メモの取り方」みたいなのが並んでませんでしたっけ。並んでました。今もあるのかな。
中身はあんまし見てないというか覚えてないんですが、持ち歩くならA6ってちょうどいいんですよね。文庫本のカバーが使えたりするし。

システム手帳ではなくノートを選んだ理由のもうひとつが、新人に締め切りが厳しい並列タスクが多数降ってくるわけでもなし、スケジュールも仕事メモもゲームの感想も全部ひっくるめて一つのノートでいいかな、研修中は自分のデスクなんてのも無いし……、と思っていたらほぼ落書き帳として4ヶ月で10冊くらい消費してしまったんですが、まあそれはそれとして。
ただこの点が結構キモで、
スケジュール帳はスケジュール管理にしか使えないけども、メモ帳やシステム手帳はスケジュール帳から落書き帳へと華麗に変身することができる。いやしない方がいいんですけど、システム手帳ならさらに落書きを無かったことにできるわけですし。素晴らしいですね。

それはそれとして、今の私にはデスクもあるし、それほど情報が溜まって忙しいわけでもないので、B5のノートを会社に置きっぱなしにする運用をしています。なんか思いついたら自分にメールを送ればいいし。
ただ最近というか、プライベートでもノートを使いたいと思う事があって。なんかプログラム書いてる時とか。でも会社のノートはアレやソレな情報が色々あるからあんまし動かしたくないし。

んで別にノート買っても良かったんですが、最近iPad買ったのでせっかくだから使えないかなぁと思ってあれやこれや試しているところです。この記事の元はiPad+スタイラスペン+手書きアプリで書かれています。

ここからが本題。iPad買いました。
Retinaモデルの9.7インチ。miniもいいけどちょっと小さいかなと思って。

なんとなくタブレット使ってみたいなぁと思って事前にタブレット使ってる友人数人に聞いてみたところ、妙なソフトを入れたり妙なデバイスをつないだりしないならiPad一択じゃないのという感じだったのでiPadにしました。
買ってみた結果、サイズはまあ人に見せたりするならこのサイズだろうけど、寝ながら使うとか歩きながら使うならminiがいいんじゃないでしょうかという感じですね。いやminiは使ってないのでわかんないんですが、ついでに他のタブレットの事も知りません。
大きくていいところは、画面が大きいことですね。字も大きく書ける。

手書き性能については、スタイラスペンはBAMBOOを使っていますが、これは結構いい。ただ私は普段は万年筆を使っているので、ペンを立てて少し力を入れて書くのに慣れなくて最初ちょっと手こずりました。シャーペンやボールペンに近い感じじゃないかと思います。

アプリは無料のUPAD Liteを使っています。評判よかったので。
あとは有料ですがNoteshelfというのも書き味が良いと評判で、実際良かった。誤入力防止機能(手をついても入力されにくくなる)があるので電車内で使うならこっちかなぁ。どちらにしても電車内では使いづらいですが。
システム手帳的に使うなら何にしても有料アプリを買った方が良さそうでした。

慣らし運転のつもりがずいぶん書いてしまいました。
テキスト起こし面倒かと思ったけど推敲だと思えば大した手間でもないですね。

やはり来世は文具屋になるべきでは。

ノートにこだわりが出てくる

久しぶりに日記的な文章を。あ、お酒は飲んでません。

最近、主戦場が徐々にソースコード以外の部分にも及び始めていて、それにともない武器の優位性や重要度も変化しつつあって、つまりノートをまたよく使うようになってきました。雑多な色々を整理したいならいまだに手書き最強な気がします。ここ半年くらいはソース書いてるだけだったのでほとんど要らなかったんですが。
メイン武器じゃないなら別に大してこだわる必要はなくて、例えばノート以外だと半年前までVimはvimrcすら書いてなかったしキーボードも安物でしたし。うーん何の仕事してたんだろう。

で、ノートの話です。

仕事でノートを使いたい場合は会社が支給してくれるんですが、そのノートが2種類あって。ひとつは会社オリジナルのノート、もうひとつは普通のいわゆる大学ノート。
私はずっと大学ノートの方を使ってたんですが、最近会社ノートがリニューアルされて、そのタイミングで大学ノートの方が支給されなくなってしまって、会社ノートしか無いのでとりあえず使っていたんですけど、非常に使いづらくてイライラする。
というかそもそもノートくらい使いやすいの自分で選べよという気もしますけどね。会社にいる時の仕事にしか使わないので、これで年収が増えるとかいうわけではないんだけど。

まあ前置きはいいとして、
会社ノートが気に入らないということは逆になにがしかこだわりがあるんじゃないかなと思って、わざわざコンビニとかではなく文具屋に出かけていくということは漠然と良いノート像があるんだろうなぁ。いや文具屋はコンビニより近所にあるんですが。せっかくだから銀座の伊東屋にも出かけてみようかなぁとかいう気分になるというのは、こだわりがあるんでしょう。

ということで何にこだわっているのか書き出してみることにしました。

大きさ

A6からB5くらい。
会社でしか使わないし移動しながら使うこともないので小さい必要は無くて、むしろ1日分とか1テーマ分とかを1ページに収めたいので大きくていい。でも打ち合わせとかそれなりに持ち歩くし、机が無い時もよくあるからあんまし大きくない方がいい。A4は大きすぎる。
仕事以外でも使ってて持ち歩いてた時はA6が良かったですけど、それより大きくてB5くらいまでがいいですね。

枚数・重さ

1テーマで60ページ使い切るとかいう事は滅多に無いので30枚でもいい。むしろ移行時期に2冊持っててもいいくらいの厚さ軽さがいい。
ただまあ40枚とか60枚とかでも別にいい。分厚くなければ。
FreeBSDのソース読んでた時は一瞬で1冊埋まりましたけど。

強度

必要ならカバーを掛けるしそんなに必要無いんだけど、あんまし弱いのは面倒くさいよねぇという感じ。逆に厚くなったり重くなったりしない程度でいい。

綴じ

こだわってない気がする。
切り取れるようにミシン線なんかはついてない方がいいです。人に渡すなら別途清書するだろ。

罫線

横罫の6〜8mmくらい。8mmはちょっと大きいかなぁという気もするけど、どうせこれに沿って書くわけじゃないし。無視するのに必要なのかというと、やっぱりあった方が書きやすい気がする。少しは横に揃うし、ベースが揃うとそれだけで結構見やすくなりますよね。
5mmはB5だと小さすぎるかなぁ。小さいと本気で無視しちゃうのであまりよろしくない。
方眼も同じくうるさすぎて無視してしまう。

上余白

上部には余白が必要。まあこれは普通にテーマとか項目名を書くからなんですが、できれば余白みたいな形で広くて一定の大きさが確保されている方が良い。
白紙だとつい上から書いちゃうので、そういう意味でも罫線ついた上での余白である方が嬉しい。
日付とかなんとかの欄は端にある分にはいいけど、自由度高い方がいいです。

横余白

横の余白はできれば無しで、罫線が端まで印刷されてるのがいい。1ページ目を目次にしてテーマごとに耳を塗りつぶしたりするから。
最近のメモの書き方みたいな本によく載ってますが結構便利ですよね。

紙そのものがどうというよりペンやインクとの相性なんですが。裏写りしないとか乾きが良いとか、当たり前のようにその方がいいよねという話ですね。
ペンは万年筆で顔料系のインクを使ってますが、まあコクヨのCampusノートとかでも普通に良かったのであまり気にしてないといえば気にしてない。

白じゃなくてちょっと色がついてる方がいいかなぁという気はするものの、別にいいや。
白に黒インクだと緊張するというかちょっとひっかかる人というのは結構多いらしいというか、私もその口なので、私はインクをブルーブラックにしてるというのもある。
文具屋に行くとクリーム色系のノートも結構多いですよね。

こんなものかなぁ。
案外こだわってる気がしますけど、まあおおむね普通の大学ノートで良いという話です。Campusのスリムシリーズ横罫6mmとかは割と最強なんじゃないかと思っています。
まとめると会社ノートの気に食わない所は、上下に余計な線とか項目が印刷されている事と、重要な場所に会社ロゴが入っていてものすごく邪魔な事と、何故かインクが乾かずに汚れる事です。
議事録を書くだけならPCでよくて、スケジュール帳にもTODO管理にも日記にもスワップ領域にもできるのがノートの良さでしょう。

目下の悩みは、ソース書いてるだけならissue trackerにメモればいいんですが、それ以外の問い合わせ対応とかなんとかをやりはじめた瞬間にメモが全部手元のノートになってしまって、周りに見えなくなってしまう事ですね。清書して公開するというのがまともな解決策ではあるんですが、そんなちゃんとしたものでもないし。公開しようがしまいが結局このブログみたいな口語体で書いてるわけだし、できればそのままアップロードできるといいんだけどなぁとか。このページに書き込むとGitHubに反映されますとかだと素敵ですね。

よし、来世は文具屋になろう。

record update

Haskellのrecordを使っているとこういう事をよくやる。

data Test = T { a :: Int, b :: String }

updateA :: Test -> (Int -> Int) -> Test
updateA t f = t { a = f (a t) }

Test型のデータのaをf関数を使って更新したい。

例えばほら、Stateにはmodify関数があるわけじゃないですか。

modify :: (s -> s) -> State s ()

という感じで、sを更新する関数を引数にとる。実際とはちょっと違うけど。でもレコードでもこういう感じの事がしたい。

具体的にはこう。

update name f rec = rec { name = f (name rec) }

recordのフィールドラベルまで引数として渡したいわけです。これコンパイルできないんですけどね。

さてどうしたものだろうかと思っていたところ、2010年にHaskell-cafeで同じ事を言っている人がいらっしゃいました。
[Haskell-cafe] record update
どうやらよくあるどうしようもない話題みたいです。最初の人がやりたいことと大体同じで、例としてState.modifyを挙げるところまで同じというかまさに私もsomeStateTransformみたいな事が頻出するコードを書いていてどうにかならんもんかと思って調べ始めたんですけど。
Jonathan Geddesさんの例:

someStateTransform :: State MyRecord ()
someStateTransform = do
     modify $ \record->record{field1 = (++"!") $ field1 record}
     ...

これは書きたくないよねぇ。

で、このHaskell-cafeのrecord updateスレは結構盛り上がってて、いろんな案が出てきたんですが決定打が出ないまま終わってしまいます。話自体は結構盛り上がってて、いろんなライブラリが紹介されててそれはそれで面白かったんですが。

しょうがない、やるか。

-- \f r -> r { label = f (label r) }
upd :: Name -> ExpQ
upd label = do
    f <- newName "func"
    r <- newName "rec"
    lamE
        [varP f, varP r]
        (recUpdE
            (varE r)
            [(,) label <$> [|$(varE f) ($(varE label) $(varE r))|]]
        )

これを使ってこう。

data Test = T { a :: Int, b :: String } deriving (Show)

main :: IO ()
main = do
    let test = T 1 "abc"
    print test                  -- => T {a = 1, b = "abc"}
    print ($(upd 'a) succ test) -- => T {a = 2, b = "abc"}

TemplateHaskellで作ればいいじゃないという。いいんだけどなんか、微妙に微妙。
exercises/record/Main.hs at master · yunomu/exercises · GitHub

そしてやっぱり似たような事を考える人はいるのでした。
mkEditor - Data.SemanticEditors
この場合は式じゃなくて関数定義を作ってますけど。

どがんかならんでしょうか。

jhcをビルドする

環境:Mac OS X 10.8.2, GHC 7.4.2

jhcはだいたい下記の記事に書いてあるとおりなんですが(autoreconfやaclocalが無い時はautoconfとautomakeをMacPortsとかでインストールするとたぶん大丈夫)、いろいろ引っかかりましたので。
簡約!λカ娘(4)の紹介とjhcのすゝめ - Metasepi

darcsは公式サイトから落としてくる。
Darcs - Download Darcs
バイナリで配布されているので、解凍してパスの通ったディレクトリに置くだけ。

で、いざやってみると、

% darcs get http://repetae.net/repos/jhc
% cd jhc
% autoreconf -i
% ./configure
% make
(略)
DrIFT src/C/FFI.hs -o drift_processed/C/FFI.hs
make: DrIFT: No such file or directory
make: *** [drift_processed/C/FFI.hs] Error 1

という感じになる。DrIFTとはなんぞや。

cabalで探すとそれらしいのが見つかる。

% cabal list DrIFT                                                                                                                                        [jhc]
* DrIFT-cabalized
    Synopsis: Program to derive type class instances
    Default available version: 2.2.3.2
    Installed versions: [ Unknown ]
    Homepage: http://repetae.net/computer/haskell/DrIFT/
    License:  BSD3

* pugs-DrIFT
    Synopsis: DrIFT with pugs-specific rules.
    Default available version: 2.2.3.20120717
    Installed versions: 2.2.3.20120717
    Homepage: http://pugscode.org/
    License:  BSD3

よくわからないけどDrIFT-cabalizedはインストールできないし、pugs-DrIFTは違うものっぽい。
けどもサイトの方にソースアーカイブがおいてあるので、それを取ってきて自分でビルドすればいいじゃないということになる。
http://repetae.net/computer/haskell/DrIFT/drop/

% wget http://repetae.net/computer/haskell/DrIFT/drop/DrIFT-2.2.3.tar.gz
% tar xvzf DrIFT-2.2.3.tar.gz
% cd DrIFT-2.2.3
% make
Making all in src
make  all-am
/usr/bin/ghc  -i. -i. -hidir . -odir . -o DrIFT --make ./DrIFT.hs
  
DrIFT.hs:20:18:
    Could not find module `System'
    It is a member of the hidden package `haskell98-2.0.0.1'.
    Use -v to see a list of the files searched for.
make[2]: *** [DrIFT] Error 1
make[1]: *** [all] Error 2
make: *** [all-recursive] Error 1

うえええ

どうもhaskell98に依存してるっぽくて、cabalにあったDrIFT-cabalizedがインストールできないのもここ関係のもよう。
仕方ないのでcabalファイルを書く。こんなものでよかろう。
DrIFT.cabal

name:                DrIFT
version:             2.2.3
build-type:          Simple
cabal-version:       >=1.8

executable DrIFT
  main-is:             DrIFT.hs
  build-depends:       haskell98
  hs-source-dirs:      src

これを使ってビルドする。

% cabal-dev build
Building DrIFT-0.1.0.0...
Preprocessing executable 'DrIFT' for DrIFT-0.1.0.0...
[ 6 of 23] Compiling GenUtil          ( src/GenUtil.hs, dist/build/DrIFT/DrIFT-tmp/GenUtil.o )

src/GenUtil.hs:486:18:
    Could not deduce (Show a) arising from a use of `st'
    from the context (Integral a)
      bound by the type signature for
                 showDuration :: Integral a => a -> String
      at src/GenUtil.hs:(486,1)-(491,28)
    Possible fix:
      add (Show a) to the context of
        the type signature for showDuration :: Integral a => a -> String
    In the first argument of `(++)', namely `st "d" dayI'
    In the expression:
      st "d" dayI ++ st "h" hourI ++ st "m" minI ++ show secI ++ "s"
    In an equation for `showDuration':
        showDuration x
          = st "d" dayI ++ st "h" hourI ++ st "m" minI ++ show secI ++ "s"
          where
              (dayI, hourI) = divMod hourI' 24
              (hourI', minI) = divMod minI' 60
              (minI', secI) = divMod x 60
              st _ 0 = ""
              st c n = show n ++ c

これは普通にコンパイルエラーを直してしまう。。
src/GenUtil.hs:486行目のshowDuration関数のシグネチャでクラス制約を付け足せばよい。

- show Duration :: Integral a => a -> String
+ show Duration :: (Integral a, Show a) => a -> String

あとは普通にビルドできます(たぶん)。

% cabal-dev build
...
Linking dist/build/DrIFT/DrIFT

出来上がったものをパスが通ったディレクトリに置けばOK。

jhcに戻ってビルドする。

% make
...
pandoc jhc_man.mkd -s -f markdown -t man -s  -o jhc.1
make[2]: pandoc: No such file or directory
make[2]: *** [man] Error 1
rm jhc_man.mkd options.mkd
make[1]: *** [jhc.1] Error 2
make: *** [all] Error 2

おおぅpandocさん……。
あとはどうにかしてpandocをインストールして、sudo make installで終わりです。