bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

Haskell ドリル10 場合分け

1.概略

パターン照合」の記事で、ガードによる場合分けを説明した。しかし、関数の入り口ではなく、式の途中の中で場合分けをしたいときがある。例えば、無名関数の中でというときがそうである。

このような時利用されるのが、if式またはcase式である。

if式はは次のようになる。

if expression 
  then true-value 
  else false-valu

if expression then true-value else false-valuとなる。ここで、expressionは条件式、true-valueは真の時に返す値、false-valuは偽の時に返す値である。

case式は次のようになる。case式では、パターン照合も使うことができる。その例は、例題の中の問題で示す。

case expression of pattern -> result
                   pattern -> result
                   pattern -> result
                   .........

2.例題

問題:関数lengthListは入力されたリストの長さが20以上の時longと返し、10から19までの時はmiddleを返し、10未満の時はshortを返す。if式を用いてlengthListを実現しなさい。

解答

プログラムは次のようになる。

lengthList :: (Eq a) => [a] -> String
lengthList lst = if length lst >= 20 
                   then "long" 
                   else if length lst >= 10 
                          then "middle"  
                          else "short"                        

また、実行結果は次のようになる。

*Main> lengthList "asd"
"short"
*Main> lengthList "asdweiktgpjeokertnskfed"
"long"
*Main> lengthList "asdweiktgpje"
"middle"                     

問題:空のリスト、一要素のリスト、複数要素のリストを場合分けする関数listKindを作成しなさい。

解答
プログラムは次のようになる。

listKind :: (Eq a) => [a] -> String
listKind lst = case lst of [] -> "Empty" 
                           [_] -> "Singleton" 
                           _:_ -> "List"                        

実行結果は次のようになる。空のリストはEmpty、一要素のリストはSingleton、複数要素のリストはListと出力される。

*Main> listKind "a"
"Singleton"
*Main> listKind ""
"Empty"
*Main> listKind "asd"
"List"
*Main> listKind [1,2,3]
"List"
*Main> listKind [1]
"Singleton"                       

3.問題

それでは問題を解いてみる。

問題1:例題の最初の問題lengthListを、ガード | を用いて表せ。

問題2:例題の二番目の問題lengthListを、caseを用いずにパターン照合だけで表しなさい(即ち、listKindの引数をそれぞれのパターンで表す)。

問題3:ifを用いて、入力された値が100以上の時はlargeと、10以上の時はmiddleと、それ以外の時はsmallと出力する関数を作成しなさい。

問題4:問題3を、ガード | を用いて表せ。

問題5:caseを用いて、次の関数を作成しなさい。関数への入力は対である。対の左側の要素を数字であり、右側の要素は文字である。数字が0であるときFalseを、それ以外の時Trueを出力する。

問題6:問題5をcaseを用いずにパターン照合だけで表しなさい。

問題7:問題5をifを用いて作成しなさい。

問題8:関数zipと無名関数を用いて次の関数を実現しなさい。この関数は、二つの数列を入力した時、次のように、真理値を対とするリストを出力する。両方の数列とも、それぞれの要素が、奇数であればFalseに、偶数であればTrueに変更する。例えば、入力が、[1,3..]と[2,4..]の時は、[(False, True),(False, True),(False, True),...]が出力される。

問題9:問題8において、数が100以上の時はlargeと、10以上の時はmiddleと、それ以外の時はsmallに変更するようにしなさい。

問題10:問題8において、caseを用いて、苗字と名前のリストを入力したとき時、イニシャルのリストを出力しなさい。例えば、["Tanaka", "Sato",..]が苗字のリストで、["Hanako", "Taro",..]が名前のリストである時、["HT","TS"..]を出力する。