ねこさんは数値データをテキストファイルでやり取りすることが多いのですが、Haskellでの実数データの読み込みは互換性の観点からすると都合がよろしくありません。read関数だけでなくParsecにもfloatというパーサが用意されているらしいのですが、これでは使い勝手が良くないのです。こちらにfloatパーサを使いつつ改善したパーサが紹介されていますが、Fortranの出力形式にも対応して欲しいねこさんには不満が残ります。
仕方が無いのでParsecの練習を兼ねて自前でパーサを組んでみることにしました。
realNum :: Parser Double
realNum = do sign <- option 1 (do s <- oneOf "+-"
return \$ if s=='-' then -1 else 1)
int <- option 0 cntNum
option '.' (char '.')
frac <- option 0 cntNum
exp <- option 0 (do oneOf "eEdD"
e <- intNum
return \$ e)
return \$ (fromIntegral sign) *
(fromIntegral int + toFrac (fromIntegral frac)) *
(10**(fromIntegral exp))
where
toFrac n = if n<1 then n
else toFrac \$ n/10
cntNum :: Parser Int
cntNum = do n <- many1 digit
return \$ (read n :: Int)
intNum :: Parser Int
intNum = do sign <- option 1 (do s <- oneOf "+-"
return \$ if s=='-' then -1 else 1)
num <- many digit
return \$ sign * (read num)
初めて書いた割には結構それなりに動いているようです。よかった。
話は変わりますが、代数的データ型を使ってコードを書いているとデバッグ時に「(Show ~)のインスタンスがないよー?」と怒られてちょっと悲しいのですが、これを解決するには当然(Show ~)のインスタンスを定義すればいいと。
data PointType = Point { x :: Double, y :: Double }
instance Show PointType where
show (Point x y) = "Point " ++ (show x) ++ " " ++ (show y)
これでデバッグしやすくなりました。
ところで、Haskellにはsprintfに相当する関数はないのでしょうか?とりあえずは実数の出力形式を細かく指定できればねこさんには十分なのですが。
2 件のコメント:
Show については、
data Point = Point {x :: Double, y :: Double} deriving (Eq,Show)
とかやるとよいです。
printf は
http://www.haskell.org/ghc/dist/current/docs/libraries/base/Text-Printf.html
ってのがありますが、
http://www.haskell.org/ghc/dist/current/docs/libraries/base/Numeric.html
のほうがよいかも。
>匿名さん
このような僻地へお越しありがとうございますー。
めったに人が来ませんのでホントに嬉しいです。特にHaskellにお詳しい方ならなおさらです!
お返事はこちらのエントリーにも書かせて頂きました。↓
http://noranekosan.sakura.ne.jp/weblog/2008/11/haskell-4.html
コメントを投稿