計算機科学のブログ

コンテキストでの型の操作 Applicative型クラス:関数をコンテキスト内で使用する ユーザー入力、Maybe型、<$>演算子(Functor)と<*>演算子

入門Haskellプログラミング (Will Kurt(著)、株式会社クイープ(監修、翻訳)、翔泳社)のUNIT5(コンテキストでの型の操作)、LESSON 28(Applicative型クラス:関数をコンテキスト内で使用する)、28.5(練習問題)Q28-3の解答を求めてみる。

コード

import qualified Data.Map as Map

data RobotPart = RobotPart { name :: String
                           , cost :: Double} deriving Show

leftArm :: RobotPart
leftArm = RobotPart { name = "左腕", cost = 1000}

rightArm :: RobotPart
rightArm = RobotPart { name = "右腕", cost = 1025}

robotHead :: RobotPart
robotHead = RobotPart { name = "頭", cost = 5092.25}

leftLeg :: RobotPart
leftLeg = RobotPart { name = "左足", cost = 975}

rightLeg :: RobotPart
rightLeg = RobotPart { name = "右足", cost = 1000}

partsDB :: Map.Map Int RobotPart
partsDB = let keys = [1..5]
              vals = [leftArm,
                      rightArm,
                      robotHead,
                      leftLeg,
                      rightLeg]
              keyVals = zip keys vals
           in Map.fromList keyVals

getID :: IO Int
getID = do read <$> getLine

getCost :: Maybe RobotPart -> Maybe Double
getCost part = cost <$> part

minPart :: Maybe RobotPart -> Maybe RobotPart -> Maybe RobotPart
minPart part1 part2 = let cost1 = getCost part1
                          cost2 = getCost part2
                          minCost = min <$> cost1 <*> cost2
                      in if minCost == cost1
                         then part1
                         else part2

printPart :: Maybe RobotPart -> IO ()
printPart Nothing = print "Invalid id"
printPart (Just part) = putStrLn (mconcat ["安いのは", name part, "で", show (cost part)])

main :: IO ()
main = do
    putStrLn "2つのIDを入力"
    id1 <- getID
    id2 <- getID
    let part1 = Map.lookup id1 partsDB
    let part2 = Map.lookup id2 partsDB
    let part = minPart part1 part2
    printPart part

入出力結果(Terminal, Zsh)

% ghc sample3.hs
Loaded package environment from /Users/…/.ghc/x86_64-darwin-8.10.5/environments/default
[1 of 1] Compiling Main             ( sample3.hs, sample3.o )
Linking sample3 ...
% ./sample3 
2つのIDを入力
1
2
安いのは左腕で1000.0
% ./sample3 
2つのIDを入力
1
3
安いのは左腕で1000.0
% ./sample3 
2つのIDを入力
1
4
安いのは左足で975.0
% ./sample3 
2つのIDを入力
4
5
安いのは左足で975.0
% ./sample3 
2つのIDを入力
4
6
"Invalid id"
%