Haskell Language
算術
サーチ…
前書き
ハスケルでは、すべての式(それらに作用する数値定数と関数を含む)は決定可能な型を持っています。コンパイル時に、型チェッカは、それを構成する基本関数の型から式の型を推論します。データはデフォルトでは不変なので、型キャスト操作はありませんが、データをコピーして理由の中で型を一般化または特殊化する関数があります。
備考
数値の型クラス階層
Num
は、数値型の階層構造の階層にあります。その特徴的な操作といくつかの一般的なインスタンスが以下に示されています(Preludeに加えてData.Complex
ものにデフォルトでロードされるData.Complex
)。
λ> :i Num
class Num a where
(+) :: a -> a -> a
(-) :: a -> a -> a
(*) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
{-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-}
-- Defined in ‘GHC.Num’
instance RealFloat a => Num (Complex a) -- Defined in ‘Data.Complex’
instance Num Word -- Defined in ‘GHC.Num’
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Int -- Defined in ‘GHC.Num’
instance Num Float -- Defined in ‘GHC.Float’
instance Num Double -- Defined in ‘GHC.Float’
Num
を必要とし、「除算」 (/)
と数の逆数という概念を導入したFractional
クラスをすでに見てきました。
λ> :i Fractional
class Num a => Fractional a where
(/) :: a -> a -> a
recip :: a -> a
fromRational :: Rational -> a
{-# MINIMAL fromRational, (recip | (/)) #-}
-- Defined in ‘GHC.Real’
instance RealFloat a => Fractional (Complex a) -- Defined in ‘Data.Complex’
instance Fractional Float -- Defined in ‘GHC.Float’
instance Fractional Double -- Defined in ‘GHC.Float’
Real
クラスは実数をモデル化します。これはNum
とOrd
必要とするため、順序付けられた数値フィールドをモデル化します。反例として、複素数は順序付けされたフィールドではありません (つまり、自然順序付け関係を持っていません)。
λ> :i Real
class (Num a, Ord a) => Real a where
toRational :: a -> Rational
{-# MINIMAL toRational #-}
-- Defined in ‘GHC.Real’
instance Real Word -- Defined in ‘GHC.Real’
instance Real Integer -- Defined in ‘GHC.Real’
instance Real Int -- Defined in ‘GHC.Real’
instance Real Float -- Defined in ‘GHC.Float’
instance Real Double -- Defined in ‘GHC.Float’
RealFrac
は丸められた数字を表します
λ> :i RealFrac
class (Real a, Fractional a) => RealFrac a where
properFraction :: Integral b => a -> (b, a)
truncate :: Integral b => a -> b
round :: Integral b => a -> b
ceiling :: Integral b => a -> b
floor :: Integral b => a -> b
{-# MINIMAL properFraction #-}
-- Defined in ‘GHC.Real’
instance RealFrac Float -- Defined in ‘GHC.Float’
instance RealFrac Double -- Defined in ‘GHC.Float’
Floating
(暗示たFractional
)有限小数拡張を有していなくてもよい定数及び動作を表します。
λ> :i Floating
class Fractional a => Floating a where
pi :: a
exp :: a -> a
log :: a -> a
sqrt :: a -> a
(**) :: a -> a -> a
logBase :: a -> a -> a
sin :: a -> a
cos :: a -> a
tan :: a -> a
asin :: a -> a
acos :: a -> a
atan :: a -> a
sinh :: a -> a
cosh :: a -> a
tanh :: a -> a
asinh :: a -> a
acosh :: a -> a
atanh :: a -> a
GHC.Float.log1p :: a -> a
GHC.Float.expm1 :: a -> a
GHC.Float.log1pexp :: a -> a
GHC.Float.log1mexp :: a -> a
{-# MINIMAL pi, exp, log, sin, cos, asin, acos, atan, sinh, cosh,
asinh, acosh, atanh #-}
-- Defined in ‘GHC.Float’
instance RealFloat a => Floating (Complex a) -- Defined in ‘Data.Complex’
instance Floating Float -- Defined in ‘GHC.Float’
instance Floating Double -- Defined in ‘GHC.Float’
注意: sqrt . negate :: Floating a => a -> a
などの式は使用しsqrt . negate :: Floating a => a -> a
は完全に有効で、 NaN
( "not-a-number")を返すことがありますが、これは意図した動作ではない可能性があります。そのような場合、複雑なフィールド(後で示す)を操作したいかもしれません。
基本的な例
λ> :t 1
1 :: Num t => t
λ> :t pi
pi :: Floating a => a
上記の例では、型チェッカーは、2つの定数の具体的な型ではなく、型クラスを推論します。 Haskellでは、 Num
クラスは最も一般的な数値クラス(整数と実数を含むため)ですが、 pi
はゼロでない小数部分を持つため、より特殊化されたクラスに属している必要があります。
list0 :: [Integer]
list0 = [1, 2, 3]
list1 :: [Double]
list1 = [1, 2, pi]
上記の具体的なタイプは、GHCによって推論されました。以下のような、より一般的な種類のlist0 :: Num a => [a]
働いているだろうが、(1がコンス場合などをも維持するために困難であったであろうDouble
のリストへNum
による上記に示した注意事項に、複数可)。
`(分数int)を推論できませんでした...`
タイトルのエラーメッセージは一般的な初心者のミスです。それがどのように発生し、どのように修正するかを見てみましょう。
数値リストの平均値を計算する必要があるとします。次の宣言はそれを行うようですが、コンパイルされません:
averageOfList ll = sum ll / length ll
問題は分裂(/)
関数にあります。シグネチャは(/) :: Fractional a => a -> a -> a
ですが、分母の上の場合( length :: Foldable t => ta -> Int
)タイプのものであるInt
(及びInt
に属していないFractional
クラス)したがって、エラーメッセージ。
エラーメッセージはfromIntegral :: (Num b, Integral a) => a -> b
修正できます。この関数は任意のIntegral
型の値を受け入れ、 Num
クラスに対応する型を返します。
averageOfList' :: (Foldable t, Fractional a) => t a -> a
averageOfList' ll = sum ll / fromIntegral (length ll)
関数の例
どのようなタイプの(+)
ですか?
λ> :t (+)
(+) :: Num a => a -> a -> a
sqrt
のタイプは何ですか?
λ> :t sqrt
sqrt :: Floating a => a -> a
sqrt . fromIntegral
のタイプは何ですか? sqrt . fromIntegral
?
sqrt . fromIntegral :: (Integral a, Floating c) => a -> c