UNIX Domain Socket を使う (クライアント編)
UNIX Domain Socket に対して echo チックなことをやるアプリケーション。本家 echo と同様、引数をそのまま出力する。複数の引数がある場合には、これらを空白で区切る。
本家 echo と違うのは、ソケットファイルのパスを受け取らなければならないということ。
空白で区切るところだけ凝った。あとは素直な実装。
import Data.List (intersperse) import IO (hPutStrLn, stderr) import System.Environment (getArgs) import Network.Socket (Socket, socket, Family(AF_UNIX), SocketType(Stream), SockAddr(SockAddrUnix), connect, send) -- 指定パスの Unix Domain Socket を開く。 -- open :: FilePath -> IO Socket open path = do sock <- socket AF_UNIX Stream 0 ready sock where ready sock = do connect sock (SockAddrUnix path) return sock -- ソケットにメッセージを送信する。 -- echo :: Socket -> String -> IO () echo sock msg = send sock msg >> return () -- ソケットに指定の全メッセージを送信する。各メッセージの間には空白文字 -- を挟む。 -- 各メッセージを送信するアクションのリストと、空白文字を送信するアクシ -- ョンを用意する。空白文字送信アクションをリストの各アクションの間に挟 -- む。このリストのアクションを先頭から逐次実行することで、メッセージ -> -- 空白 ->メッセージ -> 空白 .. -> メッセージの順にソケットへ書き込む。 -- echoAll :: Socket -> [String] -> IO () echoAll sock msgs = sequence_ actions where sendActs = map (echo sock) msgs sendWS = echo sock " " actions = intersperse sendWS sendActs main = do args <- getArgs case args of [] -> usage (path:msgs) -> doEcho path msgs where usage = hPutStrLn stderr "PROG <path> [MSG1, MSG2..]" doEcho path msgs = do sock <- open path echoAll sock msgs
IO バリバリの Haskell プログラムは Haskell っぽくないと言われることもある。確かに命令型っぽい見た目にはなる。ただ、Haskell であることの恩恵は十分あると思う。遅延評価によってアクションをお手軽に値として扱えることや、モナドをタグに見立てたアクションの型安全性など、これはもうめちゃくちゃ嬉しいことでないかな。