0

私は Haskell を学ぼうとしていて、再帰関数に関する本の問題に取り組んでいました。

> If   X_1 = 1 then X_2 = 1 + X_1 = 2, X_3 = 1 + X_1 + X_2
      or when it is 5,  X_5 = 1 + X_4 + X_3 + X_2 + X_1 = 16, and so forth. 

Haskellでこれをやってみました:

test :: Int -> Int
test 1 = 1
test n = sum[test n .. test (n-1)]

しかし、出力は常に1です。最初に関数ガードを実行してから合計する必要があると思いますが、再帰動作でそれを行う方法がわかりません。

4

2 に答える 2

5

開始するのに適した場所は、リスト内包表記です。

[ test i | i <- [1..5] ]

意味

[ test 1, test 2, test 3, test 4, test 5 ]

あなたが今それを解決できるかどうか見てください。

1を追加することを忘れないでください!

于 2013-02-07T09:26:20.227 に答える
3

コードのこの部分は Haskell の範囲です

[test n .. test (n-1)]

範囲は、左の数字と右の数字を計算し、左の数字から右の数字までのすべてのステップを含むリストを作成することによって機能します。そう:

[1 .. 6] --> [1,2,3,4,5,6]
[5 .. 9] --> [5,6,7,8,9]

ご覧のとおり、デフォルトのステップは 1 であるため、左の数値が右の数値よりも大きい場合、空のリストが得られます。

[4 .. 3] --> []

余談ですが、別の番号を指定してデフォルトのステップをオーバーライドできます。

[1, 3 .. 6] --> [1,3,5] -- step is 2
[8, 6 .. 3] --> [8,6,4] -- step is -2

ご覧のとおり、ステップ サイズが 1 以外の場合は、結果のリストに含まれるものに注意する必要があります。これは特に負のステップの場合に当てはまり、 のような整数でないステップがある場合はなおさらです[1, 1.25, .. 2.1]。範囲を使用して非整数のリストを生成することはほとんどありません。

あなたのソリューションには、次の行があります

test n = sum[test n .. test (n-1)]

範囲の規則によれば、これはうまくいかないはずです。プログラムが範囲からリストを作成しようとすると、それがtest n範囲の左の数であるため、計算が試みられます。しかし、test nこの行全体が最初に計算しようとしているものなので、それではどこにも行きません。そのため、無限ループが発生し、プログラムがハングします。

あなたはやろうとすることができます

test n = sum[1 .. test (n-1)]

それはあなたが与えた例に近いようです。1(これはtest 1) で始まり、 で終わりますtest (n-1)。しかし、問題はその中間の値です。範囲には 1 のステップがあるため、最終的には次のようになります。

[1 .. test (n-1)] --> [1,2,3, ......., test (n-1)]

と同じではありません

[test 1, test 2, test 3, .... , test (n-1)]

また、範囲は一定のステップしか持てないため、デフォルトのステップをオーバーライドしたとしても、単純な範囲でこの最後の行を取得する方法はありません。これを解決するためのヒントの 1 つは、リスト内の要素の数に注目することです。

length [1 .. test (n-1)] --> test (n-1), 
  -- because [1,2,3] has 3 elements, [1,2,3,4] has 4 and so on

length [test 1, test 2, test 3, ....... , test (n-1)] --> n-1
  -- this is not quite Haskell syntax

ここでの Haskell のやり方は、正しい数の要素を持つリストを作成し、それを変換して各要素が正しいものになるようにすることです。(n-1)要素のリストをどのように作成しますか? 単純:

[1..(n-1)]

ここから、いくつかの方法で行くことができます。luqui からのリスト内包表記があります。

[test x | x <- [1..(n-1)]]

これは、各数値を範囲から取り出して に代入し、関数をにx適用すると考えることができるため、 が得られます。別の方法は、次の関数を使用することです。testx[test 1, test 2, test 3, ....... , test (n-1)]map

map test [1..(n-1)]

私はこれをtestリストの各要素に同時に適用すると考えていますが、これはリスト内包表記とまったく同じものであり、2 つの見方があります。どちらの方法でも[1..(n-1)]範囲を使用することに注意してください。

[test n .. test (n-1)]元のコードの範囲の代わりにこれらのいずれかを使用すると、ソリューションに非常に近くなります。luqui が指摘するように、足りないのは 1 を足すことだけです。

于 2013-02-07T14:09:36.153 に答える