読者です 読者をやめる 読者になる 読者になる

は は ハ ハ haskell

Haskell

は は ハ は haskell - etc9からの続きです。

条件式

Haskell の if 文は、多くの関数型言語と同じく式です。つまり、なんらかの値を返します。そして else 部がかならず必要です。
整数の絶対値を返却する関数は、条件式を使って以下のように定義できます。

abs :: Int -> Int
abs n = if n >= 0 then n else -n

実行結果は以下のようになります。

Main> abs 1
1
Main> abs (-4)
4

条件式はネストすることもできます。例えば以下のように

signum n if n < 0 then -1 else
           if n == 0 then 0 else 1

ガード

ガードを | にて列挙できます。

abs :: Int -> Int
abs n | n >= 0 = n
      | otherwise = - n

otherwise は常に True を返却するので、最後のガード条件として置いておくと良いです。必須ではないですが。
条件は以下のようにいくつも続けて定義できます。

signum n | n < 0     = -1
         | n == 0    = 0
         | otherwise = 1

前の例の条件式の定義と比べて非常に読みやすくなっています。


リスト内包表記

リスト内包表記は、以下のように | と <-(数学では∈) により定義します。

lists :: Int -> [Int]
lists n = [ x*x | x <- [1..n] ]

x <- [1..n] はジェネレータ部でカンマで区切ることで複数のジェネレータをネストすることもできます。
実行すると以下のようになります。

Main> lists 0
[]
Main> lists 4
[1,4,9,16]

ジェネレータをネストすると以下のようになります。

Hugs> [(x, y) | x <- [1, 2, 3], y <- ['a', 'b']]
[(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]


リスト内包にはガードを設けることができます。前述の例で、x が偶数の場合のみ結果に含めるようにするには以下のようにします。

lists :: Int -> [Int]
lists n = [ x*x | x <- [1..n], x `mod` 2 == 0]

4 を入力として与えると、ガードにより奇数が除外されます。

Main> lists 4
[4,16]

以下のように書いても同じですね。

lists n = [ x*x | x <- [1..n], odd x ]

where節

関数内に where 節で関数を定義できます。where で定義した関数は複数のガードにまたがって可視となります。

psquare :: Num a => a -> a
psquare x = (plus x)^2
  where
    plus n = n + 1

psquare 2 とすると (2+1) * (2+1) となり 9 が得られます。


以下のようにして

pmsquare x = (plus x) * (minus x)
  where
    plus n  = n + 1
    minus n = n -1

pmsquare 3 とすると (3+1) * (3-1) となり 8 が得られます。


let式

where 節と似ていますが、こちらは式であり値を持ちます。
上記 where 節と同じ例をlet式で書くと以下のようにできます。

psquare x = 
  let plus n  = n + 1
  in (plus x)^2
pmsquare x = 
  let plus  n = n + 1
      minus n = n - 1
  in (plus x) * (minus x)

in 以下の結果を式の値として返却します。
where 節で定義した関数のスコープはガードをまたいだのに対し、let式はガードを跨いだスコープは持ちません。


ケース文

case 文は関数定義の本体内でパターンマッチを扱います。
例えばこんな感じです。

tupler xs = case xs of
    [] -> []
    (x:xs) -> [(x,xs)]

あまり意味の無い例ですが、

Main> tupler "hoge"
[('h',"oge")]

case 文の中にガードを記載することもできます。

htupler xs = case xs of
    [] -> []
    (x:xs) | x == 'h'  -> [('H',xs)]
           | otherwise -> [(x, xs)]
Main> htupler "hoge"
[('H',"oge")]


は ハ は は haskell - etc9につづく