"Programming with Arrows" http://www.cs.chalmers.se/~rjmh/afp-arrows.pdf

の1.1 Pointfree programming のところを読む。
ポイントフリープログラミングは、パイプでつなげるような感じで、
自然にコンポーネントを組み立てるようにプログラミングができていい、と。
だけど、String -> IO String であるreadFileは、そのままでは型が合わないので
words::String -> [String]
にはつなげられない、と。
ここで普通はdo構文を使ったりすると思うけど、lisftMや>>=を使ってむりやり
ポイントフリースタイルで書く。が、もうこれだと複雑すぎていまいちだ、と。

そこで、まず
type Kleisli m a b = a-> m b
を定義する、と。これはdataやnewtypeではないので、
ただの a-> m b 型の別名。(なんでKleisliという名前なのかというと、
このタイプのfunction、つまり型がa-> m bな関数は、
モナドmのKleisli圏におけるArrow(射)だから、だそうだが、
圏論がわからんので、わけわかんない。はやくわかるようになりたい。)
左にKleisli m a b を、右にKleisli m b c をとって、
Kleisli m a c を返す演算子(>>>)を定義する。
あともうひとつ、ふつうの関数(a->b)を(Kleisli m a b)型、つまり
(a-> m b)型に変換する関数arrを定義する。

(>>>) :: Monad m =>Kleisli m a b -> Kleisli m b c -> Kleisli m a c
(f >>> g) a = do b <- f a
                 g b

arr :: Monad m => (a->b) -> Kleisli m a b
arr f = return . f

これで、readFile してwords で単語のリストにして、length で長さを調べてprintで出力するような関数は、

count = readFile >>> arr words >>> arr length >>> print
main = count "test.txt"

のように書ける。これならわかりやすいだろう、と。