map
-各要素を変更します
fold
-すべての要素を組み合わせる
scan
-実行中の「合計」を維持するすべての要素を組み合わせる-これはあなたが必要とするものです
最後まですべてを整数として保持する方が簡単です。
type PosixOffset = Integer
の文字列はlistOfTimes
、UNIX時間、増分、または誤った値である可能性があります。それを表現することMaybe (Either PosixOffset Integer)
はできますが、それは煩わしいものになる可能性があります。私たち自身を転がしてみましょう:
data Time = Unix PosixOffset | Inc Integer | Error String deriving Show
これにより、後でエラーが発生した場合に柔軟に対応できます。プログラムをでクラッシュさせ、ユーザーにメッセージをerror
表示Error
しますが、何らかの方法で再開できるようにするか、不正な値を無視します。
クラッシュする代わりにread :: String -> Integer
戻る、置き換えられる安全なバージョンを作成しましょう。Nothing
私たちはする必要がありますimport Data.Char (isDigit)
readInteger :: String -> Maybe Integer
readInteger "" = Nothing
readInteger xs | all isDigit xs = Just (read xs)
| otherwise = Nothing
readTime
これで、これをいくつかの役立つError
メッセージとともに使用できます。
readTime :: String -> Time
readTime ('u':xs) = case readInteger xs of
Just i -> Unix i
Nothing -> Error $ "readTime: there should be an integer after the u, but I got: " ++ 'u':xs
readTime [] = Error "readTime: empty time"
readTime xs = case readInteger xs of
Just i -> Inc i
Nothing -> Error $ "readTime: " ++ xs ++ " is neither a unix time nor an increment."
計画は、文字列のリストをペアのリストに変換することです(PosixOffset,Integer)
。最後PosixOffset
の情報はUNIX時間からのものであり、現在の増分です。次に、これらのペアをに変換できるようにする必要がありますUTCTime
toUTC :: (PosixOffset,Integer) -> UTCTime
toUTC (p,i) = psUTC (p+i)
Time
次に、の現在の合計を次のの合計と組み合わせる方法を知る必要がありますTime
。参考までに、最後のUNIX時間を保持します。
addTime :: (PosixOffset,Integer) -> Time -> (PosixOffset,Integer)
addTime (oldunix,oldinc) time = case time of
Unix new -> (new,0) -- If there's a new unix time, replace and reset the inc to 0.
Inc inc -> (oldunix,inc) -- If there's a new increment, replace the old one.
Error msg -> error msg -- If there's an error, crash showing it.
またはあなたが使用することができます
addTimeTolerant :: (PosixOffset,Integer) -> Time -> (PosixOffset,Integer)
addTimeTolerant (oldunix,oldinc) time = case time of
Unix new -> (new,0) -- If there's a new unix time, replace and reset the inc to 0.
Inc inc -> (oldunix,inc) -- If there's a new increment, replace the old one.
Error msg -> (oldunix,oldinc) -- If there's an error, ignore it and keep the time the same.
これで、一緒に貼り付けることができます。sをsString
に変換し、を使用してそれらをペアTime
に結合し、結果のすべてのペアをsに変換します。(PosixOffset,Integer)
scan
addTime
UTCTime
runningTotal :: [String] -> [UTCTime]
runningTotal [] = []
runningTotal xss = let (t:ts) = map readTime xss in -- turn Strings to Times
case t of
Error msg -> error msg
Inc _ -> error "runningTotal: list must start with a unix time"
Unix po -> map toUTC $ scanl addTime (po,0) ts -- scan the list adding times,
-- starting with an initial unix time
-- then convert them all to UTC
または、落ち着いてアプローチを続けるのが好きな場合はaddTimeTolerant
、
isn't_UnixTime :: Time -> Bool
isn't_UnixTime (Unix _) = False
isn't_UnixTime _ = True
runningTotalTolerant :: [String] -> [UTCTime]
runningTotalTolerant xss =
let ts = dropWhile isn't_UnixTime (map readTime xss) in -- cheerily find the first unix time
if null ts then [] else -- if there wasn't one, there are no UTCTimes
let (Unix po) = head ts in -- grab the first time
map toUTC $ scanl addTimeTolerant (po,0) (tail ts) -- scan the list adding times,
-- starting with an initial unix time
-- then convert them all to UTC