2017-07-27 4 views
1

Ich bin neu in F # und ich codiere kleine Herausforderungen, um die wesentlichen Details über die Sprache zu lernen. Ich denke, ich habe ein Problem wegen Unveränderlichkeit.F # Unveränderlichkeit, reine Funktion und Nebeneffekt

Szenario: Ich muss Höhenzeilen in der Konsole lesen, jede Zeile enthält eine ganze Zahl. Diese ganze Zahl repräsentiert die Größe eines Berges. Nach dem Lesen der Eingabe muss ich die Zeilennummer der höchsten Berge schreiben. Wenn der angegebene Index der höchste Berg ist, dann wird die Größe auf Null gesetzt, sonst verliere ich. Wiederholen Sie das Szenario, bis alle Berge auf Null eingestellt sind.

Hier ist der Code, den ich schrieb:

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() 

Dieser Code zu einer Endlosschleife wird, ich glaube, es ist, weil die

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

unveränderlich ist, so wird der Wert einmal und nach dem es höre nie wieder auf, um die Zeile zu lesen. Ich versuche, "veränderbare" Schlüsselwort für

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

zu setzen, aber es änderte nichts. Haben Sie eine Idee?

Edit: Ich weiß, dass dieser Code in eine Endlosschleife wird, weil nach dem Hinzufügen in die Hauptschleife wie folgt anmelden:

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() 

Dann habe ich dies in der Ausgabe:

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... 

Warum möchte ich den Wert erneut lesen? Weil die Werte von einer externen Quelle stammen. So ist der Arbeitsablauf ist wie folgt:

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

Warum denken Sie, dass der Code in Endlosschleife geht? –

+0

Ich habe gerade den Beitrag bearbeitet, um deine Frage zu beantworten. Es ist, weil ich es sehen kann, wenn ich die Daten im Fehlerstrom drucke. –

Antwort

5

let readlineInt() = ... eine Funktion definiert. Sein Körper wird jedes Mal ausgeführt, wenn Sie ihn anrufen. Und in diesem Fall hat der Körper einen Nebeneffekt und dieser Nebeneffekt (das Lesen von stdin) wird jedes Mal ausgeführt, wenn der Körper ausgeführt wird. Das ist also nicht dein Problem.

readAllMountainsData ist definiert als eine Liste mit den Daten von sieben Bergen. Jeder dieser Berge hat seine eigene Höhe (denn readLineInt() wird für jeden Berg einmal genannt). Diese Liste wird einmal berechnet und ändert sich danach nicht mehr. Es wird nicht jedes Mal neu berechnet, wenn Sie readAllMountainsData verwenden, da es eine Variable und keine Funktion ist (auch wenn der Name vielleicht etwas anderes vermuten lässt). Das scheint vollkommen vernünftig zu sein, denn wenn man die Bergdaten jedes Mal neu liest, ergibt das keinen Sinn.

Wenn Sie der Definition das Schlüsselwort mutable hinzufügen, können Sie die Variable neu zuweisen. Das heißt, Sie können später im Programm readAllMountainsData <- someNewValue schreiben, um den Wert der Variablen zu ändern. Da du das nie tust, ändert sich nichts.

Der Grund, dass Ihr Programm unendlich schleift, ist, dass sich mainLoop immer wieder selbst aufruft. Es hat keine Ausgangsbedingung. Um das zu beheben, sollten Sie entscheiden, wie oft Sie die Schleife/unter welcher Bedingung Sie beenden möchten, und dann diese Logik entsprechend implementieren.


In Ihrem bearbeiten geklärt Sie, dass Sie Ihre Werte neu lesen Sie möchten, so müssen Sie einfach readAllMountainsData eine Funktion machen, indem es eine Parameterliste (let readAllMountainsData() = ...) geben und es dann als eine Funktion aufrufen. Auf diese Weise erhalten Sie bei jeder Iteration neue Daten, aber die Schleife ist immer noch unendlich, es sei denn, Sie fügen eine Exit-Bedingung hinzu.

+0

Die Hauptschleife ruft sich selbst auf, weil ich möchte, dass der Schritt bis zum Ende wiederholt wird (alle Berghöhe sind auf 0 gesetzt). Ich versuche, eine Funktion mit readAllMountainsData durch Hinzufügen von() zu erstellen, aber es hat nichts geändert. –

+0

@ CedricRoyer-Bertrand Wenn Sie sich selbst anrufen möchten, bis alle Höhen null sind, muss diese Bedingung im Code enthalten sein. Momentan nennst du dich für immer, nicht bis die Höhen Null sind. – sepp2k

+0

Ok, du hast den Fehler gefunden, es war in der Tat, dass readAllMountainsData keine Funktion war. Ich habe bei meinem vorherigen Versuch einen Fehler gemacht. Ich habe die Bedingung hinzugefügt, bei 8 zu stoppen. Danke für die Erklärung auf veränderbar auch. Ich akzeptiere deinen Beitrag als Antwort. Danke noch einmal. –