モナドとわたしとコモナドスマートフォン用の表示で見るモナドとわたしとコモナド2015-06-22Haskellの型クラスを活用するHaskellの型クラスは、うまく使えば高いパフォーマンスと抽象度を両立できる、優れた仕組みである。その使い方のコツは、決して理解の難しいものではない。小さな性質、大きな恩恵プログラマは大きなものを小さく見せがちだ。オブジェクト指向プログラミングに慣れている人がやりがちなアンチパターンとして、欲しい機能と、それを分割する基準が現実に寄りすぎていて、一つ一つが巨大というものがある。普通のプログラミングではありえない例かもしれないが、たとえば家を作りたいことを考える。トイレ」「風呂」のように設備ごとに分けた抽象化をしたいと考えるだろう。確かにこれは理に適っているように見える。これらの設備を型クラスでまとめるのは悪手だ。風呂やトイレには水を利用できるという性質が、冷蔵庫には電気が必要だ。部屋と部屋は壁で仕切られ、場合によっては扉があるかもしれない。水を伝えるにはパイプで繋がなければいけない。電気を取り出すにはコンセントで繋ぎ、扉を取り付けるには蝶番がなければ。繋ぐと一言で言っても、その方法は様々である。「繋がれたものは安定して機能を果たせる」という論理的な共通点から、様々な操作を「繋ぐ」という言葉で抽象化している。このレベルの話でやっと型クラスが有用になってくる。コンパイル時の定めSemigroupという型クラスがsemigroupsパッケージで定義されている。これは半群という代数的構造を表すクラスで、二項演算(<>)を持つ。cが成り立たななければいけない。Semigroupの例として、リストとその結合、数値の足し算や掛け算などがある。()の場合は何もしない。b)型さえはっきりしていれば、コンパイル時にインスタンスが選択され、(<>)はふさわしい実装で置き換えられる。これに関してパフォーマンスで心配する必要はないし、繰り返し使うのにも適している。仮に風呂が型クラスのメソッドだったとしても、風呂をたくさん置く家はあまりないだろう。7.10以前は、Preludeのfoldrなどの関数はリスト専用だった。7.10以降は、Foldableのメソッドとして一般化されている。これによって今までのコードが遅くなる心配をする必要はない。実際にリストに対するfoldrを含むプログラムを-ddump-rule-rewritesオプションをつけてコンパイルすると、リスト専用のfoldrに置換されるのを確認できる。GHC.Types.Intコンパイル時の置換をより積極的に利用した例としてlensパッケージも挙げられる。Lensはゲッターとセッターの対から構築されるアクセサである。s))viewやsetは、Lensが使うfmapをConstやIdentityのために特殊化することでゲッター、セッターとしての機能を取り出している。b)実際に式を変形するとその挙動は明らかだ。lensパッケージはcoerceなども併用することで、以下の変形をコストなしで実現している。bこうしてみると、型クラスは「複雑な処理をまとめる」というよりは「特定の性質を持つ処理を最適な形で具体化する」ものと見ることができる。型クラスは半群や関手のような代数的な構造であり、ライブラリとして既に定義されている場合がほとんどである。その観点では、ユーザーである私たちは、あえて新しいクラスを定義する必要は基本的にないのだ。私はHaswerkというMinecraftクローンを開発しているが、今のところ独自のクラスは宣言しておらず、これから作る予定もない。Haskellのエコシステムに鎮座する型クラスの数々を最大限に活用しよう。型クラスは抽象化のポータル(玄関口)である。クラスのメソッドを使うことで、あるいはインスタンスを定義することで、互いに再利用できるコードが生まれる――インスタンスが満たす「性質」を頼りにして。joinedHaskellはてなブログをはじめよう!fumiexcelさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。