テニスの勝負判定コード

キミのコードが汚い理由 - ITmedia エンタープライズ
Javaのコードは修正後もちっとも美しさを感じなかったのでスルーしていたのですが、美しいコード? - sshi.ContinualRubyのコードが美しく感じたので、僕もHaskellに移植してみました。Rubyのコードは副作用がある部分が分離されているので、Haskellに移植するのが楽でした。ちょっと前までは副作用なんて全然気にせずにコードを書いていたのですが、Haskellを使うようになって、とても気にするようになりました(というか気にしないと、Haskellらしいまともなプログラムが書けないような)。

module Main (main) where

import System (getArgs)

type Player = (String, Int)

data Result = Win | Lead | Tie deriving (Eq, Show)

judgeTennisGame :: Player -> Player -> (Result, Player, Player)
judgeTennisGame playerA @ (_, gameA) playerB @ (_, gameB) =
  (result leader loser, leader, loser)
  where
    (leader, loser)
      | gameA > gameB = (playerA, playerB)
      | otherwise     = (playerB, playerA)

    result leader @ (_, gameLeader) loser @ (_, gameLoser)
      | gameLeader == gameLoser          = Tie
      | gameLeader == 7                  = Win
      | gameLeader == 6 && gameLoser < 5 = Win
      | otherwise                        = Lead

showTennisGameResult :: (Result, Player, Player) -> String
showTennisGameResult (result, (nameLeader, gameLeader), (_, gameLoser))
  | result == Win  = nameLeader ++ " wins the set " ++ score 
  | result == Lead = nameLeader ++ " leads "        ++ score 
  | result == Tie  = "Set is tied at " ++ show gameLeader
  | otherwise      = error "not reach here."
  where
    score = show gameLeader ++ " - " ++ show gameLoser

main :: IO ()
main = do
  args <- getArgs
  putStrLn $ showTennisGameResult $ judgeTennisGame
    ("PlayerA", (read $ args !! 0))
    ("PlayerB", (read $ args !! 1))