2017-07-27 3 views
1

私はF#に新たなんだと私は言語についての核心ザラザラの詳細を学ぶために少しの課題をコーディングしています。私は不変のために問題があると思う。F#不変性は、純粋な機能や副作用

シナリオ: Iコンソールの高ラインを読まなければならない、各行が1つの整数を含んでいます。その整数は山の大きさを表します。 入力を読み終えたら、最高の山々の行番号を書く必要があります。 与えられたインデックスが最高の山の場合、サイズはゼロに設定されます。 すべての山のサイズがゼロになるまでシナリオを繰り返します。

ここで私が書いたコード:

open System 

type Mountain = {Id:int; Height:int} 

let readlineInt() = int(Console.In.ReadLine()) 
let readMountainData id = {Id = id; Height = readlineInt()} 
let readAllMountainsData = [ for a in 0 .. 7 do yield readMountainData a ] 

let rec mainLoop() = 
    let mountains = readAllMountainsData 
    let highestMountain = mountains |> List.maxBy (fun x -> x.Height) 

    printfn "%i" highestMountain.Id 
    mainLoop() 

mainLoop() 

このコードは無限ループに起こっている、私は

let readlineInt() = int(Console.In.ReadLine()) 

は不変なので、値は、一度設定されていると、それはだ後からだと信じています行を読むために決して再び停止しないでください。

let mutable readAllMountainsData = [ for a in 0 .. 7 do yield readMountainData a ] 

については、「変更可能」のキーワードを入れようとしていますが、何も変わりませんでした。 ご存知ですか?

編集:私はこのコードが原因の追加以下のようにメインループにログインした後に無限ループに入っていることを知っている

let rec mainLoop() = 
    let mountains = readAllMountainsData 
    Console.Error.WriteLine("Mountain Count:{0} ", mountains.Length) 
    mountains |> List.iter (fun x -> Console.Error.WriteLine("Mountain Id:{0} Height:{1}", x.Id, x.Height)) 
    let highestMountain = mountains |> List.maxBy (fun x -> x.Height) 

    printfn "%i" highestMountain.Id 
    mainLoop() 

は、その後、私は出力でこれを持っている:

Standard Error Stream: 

Mountain Count:8 
Mountain Id:0 Height:9 
Mountain Id:1 Height:8 
Mountain Id:2 Height:7 
Mountain Id:3 Height:6 
Mountain Id:4 Height:5 
Mountain Id:5 Height:4 
Mountain Id:6 Height:3 
Mountain Id:7 Height:2 
Mountain Count:8 
Mountain Id:0 Height:9 
Mountain Id:1 Height:8 
Mountain Id:2 Height:7 
Mountain Id:3 Height:6 
Mountain Id:4 Height:5 
Mountain Id:5 Height:4 
Mountain Id:6 Height:3 
Mountain Id:7 Height:2 
Mountain Count:8 
Mountain Id:0 Height:9 
Mountain Id:1 Height:8 
Mountain Id:2 Height:7 
etc... 

は、なぜ私は値を再読み込みしたいですか?値は外部ソースによって提供されるためです。したがって、ワークフローは以下のようになります。

Loop one: 
I read 8 values for the height of the mountains in the console 
I output the value of the highest mountain 

Loop two: 
I read 8 values for the height of the mountains in the console 
I output the value of the highest mountain 

Loop three: 
I read 8 values for the height of the mountains in the console 
I output the value of the highest mountain 

etc 
+1

なぜコードが無限ループに入っていると思いますか? –

+0

私はちょうどあなたの質問に答えるために投稿を編集しました。これは、エラーストリームにデータを印刷すると見ることができるからです。 –

答えて

5

let readlineInt() = ...は関数を定義します。それはあなたがそれを呼び出すたびに実行されます。この場合、本体には副作用があり、本体が実行されるたびに副作用(stdinから読み込む)が実行されます。それはあなたの問題ではありません。

readAllMountainsDataは7つの山のデータを含むリストになるように定義されます。それらの山はそれぞれ独自の高さを持ちます(readLineInt()は山ごとに1回呼び出されるため)。このリストは1回計算され、それ以降は変更されません。 readAllMountainsDataを変数として使用するたびに再計算されるのではなく、関数ではない(たとえ名前が示唆していても)。それは理にかなっていない毎回山のデータを再読み込みすると完璧に賢明なようです。定義にmutableキーワードを追加

変数を再割り当てすることができます。つまり、変数の値を変更するために、後でreadAllMountainsData <- someNewValueをプログラムに書き込むことができます。あなたは決してそれを実際に行うことはないので、何も変わりません。あなたのプログラムが無限ループし

理由はmainLoopは常に再び自分自身を呼び出すことです。終了条件はありません。ですから、どの条件でループしたいかを決める必要があります。そして、それに応じてロジックを実装してください。あなたの編集で


は、あなたが自分の価値観を再読み込みしたいという、明確なので、あなたは単にそれをパラメータリスト(let readAllMountainsData() = ...)を与えることによってreadAllMountainsData機能を行い、その後、機能としてそれを呼び出す必要があります。この方法では、各繰り返しで新しいデータを取得しますが、終了条件を追加しない限り、ループは無限になります。

+0

メインループはそれ自身を呼び出します。なぜなら、ステップが最後まで繰り返されるからです(すべての山の高さが0に設定されています)。私はreadAllMountainsDataを使って関数を作成しようとしましたが、何も変更しませんでした。 –

+0

@ CedricRoyer-Bertrandすべての高さがゼロになるまで自分自身を呼び出す場合は、その条件をコードに記述する必要があります。現在、あなたは自分自身を永遠に呼びます。高さがゼロになるまでではありません。 – sepp2k

+0

さて、あなたはバグを見つけました。実際、readAllMountainsDataは関数ではありませんでした。私は以前の試みで間違いを犯しました。私は8で停止する条件を追加しました。変更可能な説明もありがとう。あなたの投稿を答えとして受け入れます。再度、感謝します。 –

関連する問題