Haskellを学ぶ-再帰
嘘ついた。for文あるらしい
試してないから詳細は知らない
ので、繰り返し処理をやるときは再帰呼び出しをするとのこと 適当に書いてみた
code:Haskell
main = do
-- 20から0までを出力する
let a = 20
print a
-- recrusions関数呼び出し
recrusions a
-- Break用
recrusions 0 = do
print 0
-- 受け取った引数から1を引いて表示
-- その後回帰呼び出し
recrusions n = do
tmp = n -1
print tmp
recrusions tmp
hoge var でhoge関数をvar引数で呼び出し(?)ということはわかっていたのでとりあえず書いてみた
Error出る
code:Error
parse error on input ‘=’
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'
letを付けろと言われた
相変わらずletを付ける場合と付けない場合の差がわからん…
とりあえずErrorに従ってletを付けて起動
こんどは動いた
code:output
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
0
0が一回多いぞ???
フローの問題だった
1. 引数から1を引く
2. 引いた値を出力
3. 再帰
4. 引数が0なら0を出力
というフローなので、そりゃそうよね
サクッと直した
code:Haskell
main = do
-- 20から0までを出力する
-- recrusions関数呼び出し
recrusions 20
-- Break用
recrusions 0 = do
print 0
-- 受け取った引数から1を引いて表示
-- その後回帰呼び出し
recrusions n = do
print n
let tmp = n -1
recrusions tmp
大分きれいになった
試しにBreak用の関数をコメントアウトしたら、まぁ当然のように無限ループした
気を付けないといかんね
ちょいちょい調べたら2つのことがわかった
1. 関数内のローカル変数はwhere句(?)を使ってまとめられる
2. doは複数の処理をまとめる時に使うので、処理が一つなら必要ない
更に書き直してみた
code:Haskell
-- 20から0までを出力する
-- recrusions関数呼び出し
main = recrusions 20
-- 受け取った引数から1を引いて表示
-- その後回帰呼び出し
recrusions n = do
print n
recrusions tmp
where
tmp = n-1
-- Break用
recrusions 0 = print 0
なんかめっちゃきれいになった
1. Break用の関数は順番関係あるかと思ったら関係なかった
とはいえ、条件は最初にあった方がわかりやすい気がするので後で順番は戻す
2. where内ではletを使わなくても怒られなかった
もしかして、letを付けるとグローバルな感じになるのか?
試しにrecrusionsでlet tmpを宣言(?)してmainでtmpを呼んでみた
Scope外だとコンパイラに怒られたよ…
3. mainの処理がmain = recrusions 20だけなのが個人的にとても好き
1から20の総和を出そうとして絶賛ドはまり中
仕様
1. 1から20までの総和を「num=1:Total=1」「num=2:Total=3」・・・という感じで20行出す
2. 始端と終端は引数として渡すこと(可変であること)
ハマりポイント
1. 回帰処理した時に終了判定どうしたらいいかわからない
2. 関数間の型がなんか合わない
ちょっとよくわからないので明日やる
Haskell勉強時間カウント:5.5H(+1.5H)ぐらい
出てるErrorメモ
code:Error
recrusionIncrement.hs:7:5: error:
? Variable not in scope: ptintTotal :: t -> Integer -> t1 -> t2
? Perhaps you meant ‘printTotal’ (line 9)
|
7 | ptintTotal start 0 end
| ^^^^^^^^^^
recrusionIncrement.hs:9:1: error:
? Couldn't match type ‘Char -> a0 -> m0 a0’ with ‘IO b’ ? Relevant bindings include
(bound at recrusionIncrement.hs:9:1)
|
9 | printTotal currentNum oldTotal end= do
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
recrusionIncrement.hs:15:13: error:
? Couldn't match expected type ‘a0 -> m0 a0’
with actual type ‘IO b’
? In a stmt of a 'do' block: print a
In the expression:
do let a = recordFactory currentNum currentTotal
print a
printTotal currentNum currentTotal
In a stmt of a 'do' block:
if currentNum > end then
do return
else
do let a = ...
print a
printTotal currentNum currentTotal
? Relevant bindings include
(bound at recrusionIncrement.hs:9:1)
|
15 | print a
| ^
参考
for文で書いたら?
同じような処理をJavaで書いたらこんな感じだろうか
うーん、for文使えた方がやりやすい…
慣れの問題だろうか?
code:Java-for
public static void main(String args...){
for (int i = 20 ; i>=0 ; i--){
System.out.println(i);
}
}
code:Java-while
public static void main(String args...){
int i = 20;
while(true){
if (i<0) {
break;
}
System.out.println(i);
i--;
}
}