のびのびなHaskell日記

2006-06-16

1から10までの和 その2

mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum (x-1)
main = print $ mysum 10

上のコードの3行目の括弧をはずしコンパイル後、生成された実行ファイルを実行するとエラーが出ます。

mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum x-1 --括弧をはずしてコンパイル
main = print $ mysum 10
 --実行時エラー
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize' to increase it.

なんでだろう(^_^;)

どちらが大きい?

フツケルP174のガードを使って、二つの整数xとyに関して、xがyより大きい時は、x is greater than yと表示し、xがyより小さい時はx is less than yと表示されるコードを書いてみました。

mysum :: Int -> Int -> String
mysum x y
 | x > y = "x is greater than y"
 | x < y = "x is less than y"
main = putStrLn $ mysum 2 100
 --実行結果
x is less than y

main = putStrLn $ mysum 2 100を手動デバッグ

mysum 2 100

x = 2,y = 100

最初の条件文の評価:x > y => false 次の条件文へ進む

次の条件文の評価:x < y => True "x is less than y"という文字列を呼び出し元へ返す

main = putStrLn "x is less than y"

"x is less than y"という文字列にputStrLn関数適用したので、コンソールに"x is less than y"という文字列が表示される。

1から10までの和 その1

1から10までの和を求める方法を、id:muscovyduckさんに教えて頂いたので早速試してみました。

mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum(x-1)
main = print $ mysum 10

手動でデバッグしてみました。

mysum 10 = 10 + mysum(10 - 1)

10 + (mysum 9)

10 + (9 + mysum 8)

(10 + 9) + (mysum 8)

(10 + 9) + (8 + mysum 7)

(10 + 9 + 8) + mysum 7

(10 + 9 + 8) + (7 + mysum 6)

(10 + 9 + 8 + 7) + mysum 6

(10 + 9 + 8 + 7) + (6 + mysum 5)

(10 + 9 + 8 + 7 + 6) + mysum 5

(10 + 9 + 8 + 7 + 6) + (5 + mysum 4)

(10 + 9 + 8 + 7 + 6 + 5) + mysum 4

(10 + 9 + 8 + 7 + 6 + 5) + (4 + mysum 3)

(10 + 9 + 8 + 7 + 6 + 5 + 4 ) + mysum 3

(10 + 9 + 8 + 7 + 6 + 5 + 4 ) + (3 + mysum 2)

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3) + mysum 2

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3) + (2 + mysum 1)

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 ) + mysum 1

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 ) + 1

10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1

==> 55

10にmysum関数適用することによって1から55までの和を求めることが出来るということが分かりました。

haskonhaskon2006/06/17 00:05haskellは関数呼び出しの結合のほうが強いからだと思います。
mysum x = x + mysum x-1
では、
mysum x = x + (mysum x) - 1
と、同じ結果になってしまいます
mysum x = x + mysum $ x -1
なら、うまくいくと思いますよ

muscovyduckmuscovyduck2006/06/17 00:08カッコを外すと問題が生じるのは、'-'(マイナス)も実は関数(二項演算子)だからです。関数適用の優先順位については、153ページあたりに解説があります。156ページに「関数適用の優先順位はHaskellを学習するさいの壁になりがち」とある通りですねえ。

taninswtaninsw2006/06/17 07:54mysum x = x + mysum $ x -1
は型エラーになります.$は優先順位が0の関数なので
mysum x = (x + mysum) $ (x -1)
と同じことになります。

NobiNobiKotaNobiNobiKota2006/06/17 10:24>haskonさん、muscovyduckさん、taninswさん、コメントありがとうございます(^^)
アドバイス頂いたとおり以下のようにコードを修正しましたが、依然としてエラーが出ています。
mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum $ x -1
main = print $ mysum 10
<上のコードをコンパイルしたときに表示されたエラー>
Expecting a function type, but found `a'
Expected type: Int
Inferred type: Int -> Int
In the second argument of `(+)', namely `mysum'
In the first argument of `($)', namely `x + mysum'
因みにmysum関数のところのみを修正した以下のコードもコンパイルしてみました。
mysum :: Int -> Int
mysum 1 = 1
mysum x = (x + mysum) $ (x-1)
main = print $ mysum 10
<実行したときに表示されたエラー>
Expecting a function type, but found `a'
Expected type: Int
Inferred type: Int -> Int
In the second argument of `(+)', namely `mysum'
In the first argument of `($)', namely `(x + mysum)'
二つのエラーを見比べてみると
In the first argument of `($)', namely `(x + mysum)'
この箇所の(x + mysum)の括弧の有無を除けば同じエラーが表示されていますね。
フツケルの153ページあたりも後ほど読んでみたいと思います(^^)

muscovyduckmuscovyduck2006/06/18 00:11NobiNobiKotaさん>
いえ、そうではなくて‥‥。
taninswさんは、次のことをおっしゃっているのだと思います。
・「mysum x = x + mysum $ x -1」と書くと「型エラーになります」。
・なぜなら、「mysum x = (x + mysum) $ (x -1)」と解釈されるからです。
というわけで「mysum x = x + mysum $ x -1」も「mysum x = (x + mysum) $ (x -1)」もダメで、「mysum x = x + mysum (x - 1)」と書かないとうまく動かないのです。

taninswtaninsw2006/06/18 01:59その通りです。
すいません、言葉足らずでした。

NobiNobiKotaNobiNobiKota2006/06/18 22:11私のほうこそ勘違いして済みませんでした(汗)

トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060616