Haskell 勉強メモ2

明示的な型宣言

Haskellの型宣言は2行で書く模様。こういう書き方は初めて。

removeNonUppercase :: [Char] -> [Char]
removeNonUppercase st = [c | c <- st, c `elem` ['A' .. 'Z']]

*Main> removeNonUppercase("HelloWorld")
"HW"

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z

*Main> addThree 1 2 3
6

Scalaだとこうかな。

def removeNonUppercase(st: Seq[Char]): Seq[Char] = {
  for (c <- st if ('A' to 'Z').contains(c)) yield c
}

removeNonUppercase("HelloWorld") // val res6: Seq[Char] = Vector(H, W)

def addThree(x: Int)(y: Int)(z: Int): Int = x + y + z

addThree(1)(2)(3) // val res7: Int = 6

一般的なHaskellの型

他の言語同様、Int 型がありマシンのワードサイズによって異なる模様。64ビットCPUの場合Intの範囲は -2^63〜2^63-1 なのでScalaだとLong型相当。他にInteger 型があって、これは有界ではなく大きな数値が扱える。BigInt的なものか。

factorial :: Integer -> Integer
factorial n = product [1 .. n]

*Main> factorial 50
30414093201713378043612608166064768844377641568960512000000000000
def factorial(n: BigInt) =  (BigInt(1) to n).foldLeft(BigInt(1)){ (a, b) => a * b}
factorial(BigInt(50)) // val res8: BigInt = 30414093201713378043612608166064768844377641568960512000000000000

FloatとDouble。Floatは単精度浮動小数点数、Doubleは倍精度浮動小数点型。

円の面積を求める関数で試してみる。

circumference :: Float -> Float
circumference r = 2 * pi * r

*Main> circumference 4.0
25.132742

circumference' :: Double -> Double 
circumference' r = 2 * pi * r

*Main> circumference' 4.0
25.132741228718345

Scala

def circumferenceF(r: Float): Float = 2.0f * math.Pi.toFloat * r

def circumferenceD(r: Double): Double = 2.0 * math.Pi * r

circumferenceF(4.0f) // val res9: Float = 25.132742
circumferenceD(4.0) // val res10: Double = 25.132741228718345

他にも

  • 真偽値 Bool (True, False)
  • Char 型(Unicode文字を表し、シングルクォート ' で括って表記する)
  • タブルも型。空のタプル () も型の一つで、ただ一つのあたい () のみをもつ※これはユニットと呼ばれる。