2016-11-23 8 views
1

に、に分と秒を(すなわち、この34m30sのようなもの)含まれている可能性があり、文字列を変換するためにいくつかの標準的な機能があり、その適切なMaybe Double?この場合、34m30sJust 34.5に変換します。変換する文字列 `<num>メートル<num> S``たぶんDouble`表現合計分Haskellで

+4

「ダブル」として時間を操作するのはよい理由はありますか?それを良いフォーマットで残してみませんか? ['time'](https://hackage.haskell.org/package/time-1.7)はあなたの書式から' TimeOfDay'を解析できます: 'parseTimeM False defaultTimeLocale"%Mm%Ss "" 34m30s "' – Alec

+1

数値を1つの数値に変換する必要がある場合は、分の秒数ではなく、秒数に変換します。 – chepner

答えて

2

答えは分と秒は2桁なので、parseMS "1m30s"parseMS "12m0s"両方がNothingを得た場合にのみ動作するようです。

本当に単純なパーサーが必要です。リストモナドでreadsコールを使用するものがあります。 "m"と "s"の接尾辞が付いた分と秒の部分が必要なので、 "10m"と "10m30"と "15s"はすべてNothingとなります。また、負の数と先頭の空白を受け入れるので、" 10m -30s"Just 9.5を返します。

readMS1 :: String -> Maybe Double 
readMS1 str = listToMaybe 
    [ fromIntegral (mins :: Int) + fromIntegral (secs :: Int)/60 
    | (mins, 'm':rest1) <- reads str 
    , (secs, "s")  <- reads rest1 
    ] 

説明のノート、あなたが前にこのスタイルを見ていない場合:私たちは」一部の人々はそうのように、それは同等のリストの内包表記を使用して書かれているとき、これを簡単に理解するために見つける

import Data.Maybe (listToMaybe) 

readMS :: String -> Maybe Double 
readMS str = listToMaybe $ do 
    (mins, 'm':rest1) <- reads str 
    (secs, "s")  <- reads rest1 
    return (fromIntegral (mins :: Int) + fromIntegral (secs :: Int)/60) 

リストのモナドを使用して、それぞれのreads呼び出しは、可能な構文のリストを(value,rest_of_string)のペアとして返します。 doブロックの最初の行は、文字「m」と文字列のrest1を足した整数minsの各解析を取得します。 2番目の行は、rest1の各可能な構文解析を、整数「secs」とそれに続く文字「s」とそれ以外は何も得ません。

一致が失敗した場合(たとえば、文字列の最後に「s」がない場合)、モナド/理解は空のリストを返します。それ以外の場合は、すべての可能な解析から計算されたDoublesのリストを返します(この場合、最大でも1つあります)。 listToMaybe関数は、空のリストをNothingに変え、他のリストの先頭をつかんで一意の答えを得ます。

+0

私はモナドに「警備員」の条件を追加することができますか、または負の値または秒の値> = 60を拒否するように理解することができると指摘しておきたいと思います。モナドの場合は、 –

+0

Ugh .. hit Enter早すぎる。モナドの場合、適切な場所に 'guard $ mins> = 0'と 'guard $ secs> = 0 && secs <= 59'を追加します。リストの理解では、 "mins> = 0'と' secs> = 0 && secs <= 59'節を "guard"を書かずに書くだけです。 –

2

その後、DiffTimeDoubleに変換し、TimeOfDayStringを変換するData.Time.Format.parseTimeMを使用することができます。 parseTimeMに基づい

import Data.Time 

parseMS :: String -> Maybe Double 
parseMS = fmap (realToFrac . (/ 60) . timeOfDayToTime) . parseTimeM False defaultTimeLocale "%Mm%Ss" 
関連する問題