Haskellの勉強 2日目

公開日:2015-01-05 更新日:2019-05-11

等差数列の和

test 0 = 0
test 1 = 1
test n = n + test (n - 1)

main = print (test 5)
(15)
5 + test (4)
5 + 4 + test (3)
5 + 4 + 3 + test (2)
5 + 4 + 3 + 2 + test (1)
5 + 4 + 3 + 2 + 1 なので 15

階乗

test 0 = 0
test 1 = 1
test n = n * test (n - 1)

main = print (test 5)
(120)
1 * 2 * 3 * 4 * 5 なので、120。

フィボナッチ数

fibonacci 0 = 0
fibonacci 1 = 1
fibonacci x = fibonacci (x - 2) + fibonacci (x - 1)

main = do
  print (fibonacci 10)
(55)
数式をそのまま定義できる。

フィボナッチ数を11個求める

fibonacci 0 = 0
fibonacci 1 = 1
fibonacci x = fibonacci (x - 2) + fibonacci (x - 1)

main = do
  mapM (print . fibonacci) [0..10]
0
1
1
2
3
5
8
13
21
34
55
関数 mapM に、関数とリストを渡すと、リストの各要素に対して、渡した関数を適用してくれます。

絶対値

absTest a
  | a >= 0 = a
  | a <  0 = -a

main = do
  print (absTest 0)
  print (absTest 10)
  print (absTest (-10))
0
10
10
| を使って、このように書くことも出来る。ガードと呼ぶらしい。

絶対値2

absTest a
  | a >= 0    = a
  | otherwise = -a

main = do
  print (absTest 0)
  print (absTest 10)
  print (absTest (-10)) 
0
10
10
otherwise は「さもなければ」を意味します。
a >= 0 でなければ、a = -a となる。

絶対値3

absTest a
  | a >= 0 = a

main = do
  print (absTest 0)
  print (absTest 10)
  print (absTest (-10))  --実行時にエラーになる。
0
10
該当する条件がない場合、実行時にエラーが発生します。
コンパイルは正常に終了する。

計算

calc :: Fractional a => [Char] -> a -> a -> a
calc a b c
  | a == "+" = b + c
  | a == "-" = b - c
  | a == "*" = b * c
  | a == "/" = b / c

main = do
  line1 <- getLine
  line2 <- getLine
  line3 <- getLine
  print (calc line1 (read line2) (read line3))
+     --入力
123   --入力
456   --入力
579.0
getLine で入力した文字列を取得することができます。
Enterを押すと確定となる。
サンプルでは、入力された演算子によって、計算内容を変えるようにしています。

再帰呼び出しの確認

test = do
  line <- getLine
  
  if line /= "end" 
    then test
    else print "END"
  
  print "bye"

main = do
  test
1    --入力
1    --入力
1    --入力
end  --入力
"END"
"bye"
"bye"
"bye"
"bye"
Haskell では、数式を定義していると言う感覚が強く、
あまり再帰呼び出しをしていると言う感じがしないのですが、
裏ではやはり再帰呼び出しをしているため、注意が必要です。

サンプルでは end が入力されるまで再帰呼び出しをしています。
そのため、end が入力されると、再帰呼び出しの階層分、bye と出力されています。

補助関数1

test = do
  test2
    where
      test2 = print "Test"

main = test
"Test"
where の後ろに補助関数を定義できます。この関数は、親の関数からのみ使用できます。

補助関数2

test = do
  test2
    where
      test2 = test3

test3 = do
  print "Hello"

main = do
  test
  --test2  --エラー
  test3
"Hello"
"Hello"
test2 は test の補助関数のため、main で呼び出すとエラーになります。
補助関数からは、外の関数 test3 を呼び出すことができます。

補助関数3

test a
  | a == 0 = test2 "A"
  | a == 1 = test2 "B"
  | a == 2 = test2 "C"
  where 
    test2 msg = print msg

main = test 0
"A"
ガード(|) と補助関数を組み合わせることができる。

補助関数4

test a
  | a == 0 = do
             test2 "A"
             test2 "A"
  | a == 1 = do
             test2 "B"
             test2 "B"
  | a == 2 = do
             test2 "C"
             test2 "C"
  where 
    test2 msg = print msg

main = test 1
"B"
"B"
こんな書き方もできる。

但し、以下の様に棒を伸ばすとパースエラーになる。棒は条件式があるところにだけ書く。
test a
  | a == 0 = do 
  |          test2 "A"
  |          test2 "A"
  | a == 1 = do
  |          test2 "B"
  |          test2 "B"
  | a == 2 = do
  |          test2 "C"
  |          test2 "C"
  where 
    test2 msg = print msg

main = test 1

今日の感想

Haskell と少しだけお友達になれた気がした。
数学の数式をそのまま定義できるのは面白い。
ただ、やはり構文に慣れない。
大きなプログラムを書いた時にどうなるのか。。。