開発環境
- OS X Lion - Apple(OS)
- Emacs、BBEdit - Bare Bones Software, Inc. (Text Editor)
- Haskell (純粋関数型プログラミング言語)
- GHC (The Glasgow Haskell Compiler) (処理系)
『初めてのプログラミング 第2版』(Chris Pine 著、長尾 高弘 訳、オライリー・ジャパン、2010年、ISBN978-4-87311-469-9)の12章(新しいクラスのオブジェクト), 12.6(練習問題の続き)、バースデーヘルパーをHaskellで解いてみる。
その他参考書籍
- プログラミングHaskell (オーム社) Graham Hutton(著) 山本 和彦(翻訳)
- Real World Haskell―実戦で学ぶ関数型言語プログラミング (オライリージャパン) Bryan O'Sullivan John Goerzen Don Stewart(著) 山下 伸夫 伊東 勝利 株式会社タイムインターメディア(翻訳)
バースデーヘルパー
コード(BBEdit)
sample.hs
{--
{-# OPTIONS -Wall -Werror #-}
--}
import qualified Data.Map as Map
import System.IO
import System.Time
main :: IO ()
main = do
handle <- openFile "birth_day_helper.txt" ReadMode
contents <- hGetContents handle
let a = linesToNamesAndCalendarTimes $ lines contents
ask a
ask :: Map.Map String CalendarTime -> IO ()
ask x = do
putStrLn "名前を入力"
line <- getLine
if line == ""
then putStrLn "終了"
else do let b = Map.lookup line x
if b == Nothing
then do putStrLn "一覧に名前がありません。"
ask x
else do let c = f b
d <- getAge c
putStrLn $ "誕生日: " ++ (getBirthDate c) ++
" 年齢: " ++ (show d) ++ "歳"
ask x
getAge :: CalendarTime -> IO Int
getAge a = do
let year = ctYear a
month = getIntFromMonth $ ctMonth a
day = ctDay a
now <- getClockTime
nowCal <- toCalendarTime now
let nowYear = ctYear nowCal
nowMonth = getIntFromMonth $ ctMonth nowCal
nowDay = ctDay nowCal
age = nowYear - year
if nowMonth < month || (nowMonth == month && nowDay < day)
then return (age - 1)
else return age
getBirthDate :: CalendarTime -> String
getBirthDate a =
let year = ctYear a
month = getIntFromMonth $ ctMonth a
day = ctDay a
in show year ++ ('年':(show month)) ++ ('月':(show day)) ++ "日"
linesToNamesAndCalendarTimes :: [String] -> Map.Map String CalendarTime
linesToNamesAndCalendarTimes xs = Map.fromList $ map lineToNameAndCalendarTime xs
lineToNameAndCalendarTime :: String -> (String, CalendarTime)
lineToNameAndCalendarTime xs = (getName xs, getCalendarTime xs)
getName :: String -> String
getName s = head $ splitComma s
getCalendarTime :: String -> CalendarTime
getCalendarTime s =
let a = map trim $ tail $ splitComma s
b = head a
c = last a
year = read c :: Int
d = splitSpace b
e = head d
g = last d
day = read g :: Int
month = f $ Map.lookup e monMonthMap
in CalendarTime {ctYear = year, ctMonth = month, ctDay = day}
trim :: String -> String
trim = trimLeft . trimRight
trimLeft :: String -> String
trimLeft [] = []
trimLeft (x:xs) | x == ' ' = trimLeft xs
| otherwise = x:xs
trimRight :: String -> String
trimRight [] = []
trimRight s = if last s == ' '
then trimRight $ init s
else s
splitComma :: String -> [String]
splitComma = splitDelimiter ','
splitSpace :: String -> [String]
splitSpace = splitDelimiter ' '
splitDelimiter :: Char -> String -> [String]
splitDelimiter a s =
let inner :: [String] -> String -> [String]
inner [] [] = []
inner [] (x:[]) | x == a = []
| otherwise = [[x]]
inner [] (x:xs) | x == a = inner [] xs
| otherwise = inner [[x]] xs
inner acc [] | last acc == "" = init acc
| otherwise = acc
inner acc (x:[]) | x == a = acc
| otherwise = let b = init acc
c = last acc
in b ++ [c ++ [x]]
inner acc (x:y:xs) | x == a = inner (acc ++ [[y]]) xs
| otherwise = let b = init acc
c = last acc
in inner (b ++ [c ++ [x]]) (y:xs)
in inner [] s
getIntFromMonth :: Month -> Int
getIntFromMonth a = f $ Map.lookup a monthIntMap
f :: Maybe a -> a
f (Just a) = a
f Nothing = undefined
monMonthMap :: Map.Map String Month
monMonthMap = Map.fromList $
[("Jan", January),
("Feb", February),
("Mar", March),
("Apr", April),
("May", May),
("Jun", June),
("Jul", July),
("Aug", August),
("Sep", September),
("Oct", October),
("Nov", November),
("Dec", December)]
monthIntMap :: Map.Map Month Int
monthIntMap = Map.fromList $
[(January, 1),
(February, 2),
(March, 3),
(April, 4),
(May, 5),
(June, 6),
(July, 7),
(August, 8),
(September, 9),
(October, 10),
(November, 11),
(December, 12)]
入出力結果(Terminal, runghc)
$ runghc sample.hs
sample.hs:74:8: Warning:
Fields of `CalendarTime' not initialised: ctHour, ctMin, ctSec,
ctPicosec, ctWDay, ctYDay, ctTZName, ctTZ, ctIsDST
In the expression:
CalendarTime {ctYear = year, ctMonth = month, ctDay = day}
In the expression:
let
a = map trim $ tail $ splitComma s
b = head a
c = last a
....
in CalendarTime {ctYear = year, ctMonth = month, ctDay = day}
In an equation for `getCalendarTime':
getCalendarTime s
= let
a = map trim $ tail $ splitComma s
b = head a
....
in CalendarTime {ctYear = year, ctMonth = month, ctDay = day}
名前を入力
Christopher Pine
誕生日: 2000年10月21日 年齢: 13歳
名前を入力
Christopher Plummer
誕生日: 2000年10月22日 年齢: 13歳
名前を入力
Christopher Lloyd
誕生日: 2000年10月23日 年齢: 12歳
名前を入力
haskell
一覧に名前がありません。
名前を入力
終了
$ cat birth_day_helper.txt
Christopher Alexander, Oct 18, 1936
Christopher Lambert, Mar 12, 2000
Christopher Lee, Mar 13, 2000
Christopher Pine, Oct 21, 2000
Christopher Plummer, Oct 22, 2000
Christopher Lloyd, Oct 23, 2000
The King of Spain, Feb 6, 2000
$
0 コメント:
コメントを投稿