文字列が表現する数値を得る
[*** Text版]
インポート
code: (haskell)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Read (Reader)
import qualified Data.Text.Read as T ()
リーダー関数
Integral a => Reader a: 実態はIntegral a => Text -> Either String (a, Text)です.
Fractional a => Reader a : 実態はFractional a => Text -> Either String (a, Text)です.
Reader Double : 実態はText -> Either String (Double, Text)
実際に提供されているリーダー関数は以下のものがある.符号なし整数に関しては,
code: (haskell)
decimal :: Integral a => Reader a -- ^ 符号無し整数10進表記用リーダー関数
hexadecimal :: Integral a => Reader a -- ^ 符号無し整数16進表記用リーダー関数
があります.
符号付き整数に対応するにはsigned :: Num a => Reader a -> Reader aを使って符号無し整数リーダーを符号付き整数リーダーに変換します.
-あるいは+付きの表記も読めるようになります.
code: (haskell)
signedDecimal :: Integral a => Reader a
signedDecimal = T.singed T.decimal
signedHexadecimal :: Integral a => Reader a
singedHexadecimal = T.signed T.hexadecimal
有理数については関しては以下の2つのリーダー関数が提供されています.
code: (haskell)
rational :: Fractional a => Reader a
double :: Reader Double
ratilanlとdoubleが受け入れるシンタックスは同じです.doubleの方がおよそ1桁速いのですが,有効桁が小さくなることがあります.
code: (haskell)
-- | 符号付き整数10進表記を整数に変換
decimalToIntegral :: Integral a => Text -> a
decimalToIntegral t = either (error . id)
(\ (i,rt) -> bool (error "invalid input") i (T.null rt))
(signedDecimal t)
-- | 符号付き整数16進表記を整数に変換
hexadecimalToIntegral :: Integral a => Text -> a
hexadecimalToIntegral t = either (error . id)
(\ (i,rt) -> bool (error "invalid input") i (T.null rt))
(signedHexadecimal t)
-- | 符号付き有理数10進表記を有理数(Fractional)に変換
toFractional :: Fractional a => Text -> a
toFractional t = either (error . id)
(\ (i,rt) -> bool (error "invalid input") i (T.null rt))
(T.rational t)
-- | 符号付き有理数10進表記を倍精度浮動小数点数(Double)に変換
toDouble :: Text -> Double
toDouble t = either (error . id)
(\ (i,rt) -> bool (error "invalid input") i (T.null rt))
(T.double t)
評価例
code:_
>> decimalToIntegral "12345" :: Int
12345
>> decimalToIntegral "-12345" :: Int
-12345
>> decimalToIntegral "+12345" :: Int
12345
>> decimalToIntegral "123456789012345678901234567890" :: Int
-4362896299872285998
>> decimalToIntegral "-12345" :: Word
18446744073709539271
[*** String版]
数値表現がStringの場合で,Preludeがエクスポートしている数値型(Int, Integer, Float, Doubleなど)でReadクラスインスタンスであること示す宣言がされているものについては,規定の数値表現形式になっていれば read :: Read a => String -> a 関数を使えます.
[** Numericモジュール]
インポート
code: (haskell)
import Numeric
リーダー関数
(Eq a, Num a) => ReadS a : 実態は (Eq a, Num a) => String -> [(a, String)] です.
(RealFrac a) => ReadS a : 実態は (RealFrac a) => String -> [(a, String)] です.
実際に提供されているリーダー関数には以下のものがあります.符号無し整数表記用については,
code: (haskell)
readDec :: (Eq a, Num a) => ReadS a -- ^ 符号無し整数10進表記用リーダー関数
readOct :: (Eq a, Num a) => ReadS a -- ^ 符号無し整数8進表記用リーダー関数
readHex :: (Eq a, Num a) => ReadS a -- ^ 符号無し整数16進表記用リーダー関数
があります.
リーダー関数の型はReadS aで,これはString -> [(a, String)]の型シノニムです.
したがって,このリーダー関数は,String型の入力文字列から,読み取り結果の値と残りの文字列の対のリストへの関数です.
このリーダー関数は,文字列の先頭からデータとして解釈できる部分がなくなるまで読み取ります.
与えた文字列全体を読み切れれば,読み取った値と空文字列との対だけを含むリストになります.
桁表現として使える文字集合を定め,桁表現文字と値との対応を指定して,符号無し整数n進表記用リーダーを独自定義できるように,
code: (haskell)
readInt :: Num a
=> a -- ^ 基数
-> (Char -> Bool) -- ^ 桁表現として使える文字を判定する述語
-> (Char -> Int) -- ^ 桁表現を整数に変換する関数
-> ReadS a
というリーダー生成関数が用意されています.これを使えば例えば符号無し整数36進法表記用リーダーを以下のように構成できます.
code: (haskell)
import Data.Maybe (maybe)
import Numeric
reads36 :: (Eq a, Num a) => ReadS a
reads36 = readInt 36 (maybe False (const True) . lookup36)
(maybe (error "no parse") id . lookup36)
where
lookup36 = (lookup table36)
read36 :: (Eq a, Num a) => String -> a
read36 s = bool (bool (error "no parse") (fst r) (null (snd r))) (error "no parse") (null rs)
where
rs = reads36 s
r = head r
評価例
code:_
>> read "12345" :: Int
12345
>> read "-12345" :: Int
-12345
>> read "+12345" :: Int
*** Exception: Prelude.read: no parse
>> read "0o12345" :: Int
5349
>> read "0x12abc" :: Int
76476
>> read36 "12xyz" :: Int
1997200763