ポイントフリースタイル

This entry was posted by on Tuesday, 13 June, 2006
>2つのリストが等しいかどうかを比較したい。ただし、一方が他方より短い場合、短い方に合わせるとする。 “abcdef” == “abc” が等しいようなイメージ。こういうケースは結構あるんじゃないかと思う。 > >どうするかっていうといろいろやり方がある気がするが、単純には zipWith で作れる。なかなか面白い。 > >listEquals l1 l2 = and $ zipWith (==) l1 l2 > >さて、これをポイントフリースタイルで書きたい。つまり、引数の l1 とか l2 とかを消したい。 > >これが引数ひとつの場合は簡単だ。関数合成演算子の (.) があって、 > >f . g = \a -> f (g a) > >になっているからこれを使う。上のように二引数だとどうだろう。実際に考えてみよう。まず、 > >c2 f g = \a1 a2 -> f $ g a1 a2 > >と書くところから始めよう。 > >この定義から、まず a2 を削れることがわかるだろう。 > >c2 f g = \a1 -> f . g a1 > >ここからがちょっとポイントだが、これは次のように書ける。 > >c2 f g = \a1 -> (f.) $ g a1 > >この (f.) はセクションである。とすると、 a1 も追い出せる。 > >c2 f g = (f.) . g > >うむ。 > >したがって元の話題に戻ると、 > >listEquals = (and.) . zipWith (==) > >である。美しい。 > >さらにさらに。 g が3引数関数だとどうなるか。 > >c3 f g = \a1 a2 a3 -> f $ g a1 a2 a3 > >これは、 > >c3 f g = \a1 a2 -> f . g a1 a2 > >ゆえに > >c3 f g = \a1 a2 -> (f.) $ g a1 a2 > >であるから、 c2 を使って、 > >c3 f g = c2 (f.) g = ((f.).) . g > >となる。 > >これを繰り返せば、任意の引数の数に対して、 (.) を使ってポイントフリースタイルで書けそうだ。逆に言うと、この形式のものは、 g が複数引数であるような関数合成であるということか。 > >ではつぎに、 f も引数を取るケース。 > >cb f g = \a1 a2 -> f a1 (g a2)
= \a1 -> f a1 . g
> >ここまでは簡単だが、これはちょっと面倒くさい。 a1 を右側に持ってきたい。 flip が使えそうだ。 > >= \a1 -> flip (.) g $ f a1
= flip (.) g . f
> >では f が2引数だとどうなるか。 > >cb2 f g = \a1 a2 a3 -> f a1 a2 (g a3)
= \a1 a2 -> f a1 a2 . g
= \a1 a2 -> flip (.) g $ f a1 a2
= \a1 -> flip (.) g . f a1
= (flip (.) g .) . f
> >んじゃさらに、 f の第一引数に関数 g が適用され、第二引数には関数 h が適用されるような場合。 > >branch f g h = \a1 a2 -> f (g a1) (h a2)
= \a1 -> f (g a1) . h
= \a1 -> flip (.) h $ f (g a1)
= \a1 -> flip (.) h $ (f . g) a1
= flip (.) h . (f . g)
> >f も引数欲しい。 > >branch' f g h = \a1 a2 a3 -> f a1 (g a2) (h a3)
= \a1 a2 -> f a1 (g a2) . h
= \a1 a2 -> flip (.) h $ f a1 (g a2)
= \a1 a2 -> flip (.) h $ (f a1 . g) a2
= \a1 -> flip (.) h . (f a1 . g)
= \a1 -> flip (.) h . (flip (.) g (f a1))
= \a1 -> flip (.) h . (flip (.) g . f) a1
= (flip (.) h .) . (flip (.) g . f)
> >また、 h が2引数関数の場合。 > >branch'' f g h = \a1 a2 a3 -> f (g a1) (h a2 a3)
= \a1 -> (f (g a1) .) . h
= \a1 -> ((f . g) a1 .) . h
= \a1 -> flip (.) h ((f . g) a1 .)
= \a1 -> flip (.) h ((.) ((f . g) a1))
= \a1 -> flip (.) h (((.) . (f . g)) a1)
= flip (.) h . ((.) . (f . g))
> > >まとめ >: セクションに (.) を利用すると簡単に難読化できます。ポイントフリースタイルは、用法、用量を守って使いましょう。 > >……ところでこれ、合ってるのかな……。 >

Comments are closed.