自作ライブラリとそれを使った成果物。
LLだとここまでライブラリ化するとreverse使わない場面でもメモリに溜め込みまくったり、それを解消するためにイテレータ作りまくったりする必要があるんじゃなかろうか。
それでなくとも副作用と純粋部分が分かれてない処理があるとライブラリ化しにくい。
rpコマンドはreplaceとかrepと付けたかったけど、sudo apt installしてないパッケージに同名のコマンドが複数あるらしいので。
rpコマンド、なるべくユニークな文字列にしないと危険だけど、関数名や引数の名前や順序変えた時に複数ファイル・複数箇所を修正するので地味に大活躍…。

Myfunc.hs(自作ライブラリ)
module Myfunc where

import Data.List
import Text.Printf

consnum::(Int,String) -> String
consnum (i,xs) = printf "%4d:%s" i xs

fline f = unlines.f.lines

fnumbering f = fline ((map consnum).(zip [1..]).f)

redstr::String -> String
redstr [] = []
redstr w = printf "\ESC[1m\ESC[31m%s\ESC[39m\ESC[0m" w

bluestr::String -> String
bluestr [] = []
bluestr w = printf "\ESC[34m%s\ESC[39m" w

grep w = fline (filter (isInfixOf w))

replace _ _ [] = []
replace [] _ cs = cs
replace w nw cs | w == take (length w) cs =
                        nw ++ replace w nw (drop (length w) cs)
replace w nw (c:cs) = c:replace w nw cs

putfc (f,c) = printf "%s\n%s" f c

writefc (f,c) = writeFile f c

mfptn fs f ofs output = mapM readFile fs >>=
                        return.(zip ofs).map f >>=
                        mapM_ output

mfput f fs = mfptn fs f (map bluestr fs) putfc

mfwrite f fs = let tfs = map (++ ".temp") fs in
               mfptn fs f tfs  writefc >>
               mfptn tfs id fs writefc

number.hs(ナンバリングコマンド)
import System.Environment
import Myfunc

main = getArgs >>= mfput (fnumbering id)

revnumber.hs(行番号付き行の逆順表示コマンド)
import System.Environment
import Myfunc

main = getArgs >>= mfput (fnumbering reverse)

mygrep.hs(検索文字列のある行を表示するコマンド。見つかった文字列を強調赤字で表示)
import System.Environment
import Myfunc

main = getArgs >>= \(w:fs) ->
       mfput ((replace w (redstr w)).(grep w).fnumbering id) fs

rp.hs(文字列置換コマンド)
import System.Environment
import Myfunc

main = getArgs >>= \(w:nw:fs) -> mfwrite (replace w nw) fs