wcのArrow版 via 趣味的にっき

趣味的にっき - Arrowを使ってwcコマンドを実装してみましたより

演算子じゃなくてパターンマッチっていうのが、いまひとつかっこ悪いのですが、何かいい方法ありませんかね?

趣味的にっき - Arrowを使ってwcコマンドを実装してみました

ということだったので、パターンマッチを使わずにやってみたんだけど、結局、(&&&)をたくさん使ってるので、タプルのネスト(?)の数を意識しなきゃいけなくなってしまいました。(&&&)は用法用量おまもりくださいだね。あと、個人的に関数は細かくしちゃいたい派なので、意味があるかわからないけど、関数をたくさん作りました。

$ cat wc_a.hs
module Main (main) where

import Control.Arrow 
add_t = (++) "\t"
length_s = length >>> show >>> add_t
line_w = lines >>> length_s
word_w = words >>> length_s
concat_a  = uncurry (++)
wc :: String -> String
wc =  line_w &&& word_w &&& length_s >>> (id *** concat_a) >>> concat_a

main = getContents >>= putStrLn . wc

ホントは、とことんArrow使おうと、mainのモナドの部分もKleisli(未だにそらでスペルが書けない)を使おうと思ったんだけど、getContentsがIO Stringだから使えなくてやめました。
で、結果

$ ghc -o wc_a wc_a.hs
$ wc wc_a.hs
       12      61     342 wc_a.hs
$ ./wc_a < wc_a.hs
        12      61      342

追記:(add_t *** ( add_t *** add_t))の部分が気に入らなかったので修正

さらに追記:MaDさんより、const使えば、getContentsもKleisli(最近はKleisleとスペルミスを犯すようになってきました)が使えるとのこと。やってみました。

module Main (main) where

import Control.Arrow 
add_t = (++) "\t"
length_s = length >>> show >>> add_t
line_w = lines >>> length_s
word_w = words >>> length_s
concat_a  = uncurry (++)
wc :: String -> String
wc =  line_w &&& word_w &&& length_s >>> (id *** concat_a) >>> concat_a
wc_p = Kleisli ( const getContents) >>> arr wc >>> Kleisli putStrLn

main = runKleisli wc_p ""

runKleisliがm a b -> a -> m bだから、かなりmainがキモイことに。使い方は、ホント考えないとな