2017-07-27 50 views
1

我是F#的新手,我正在編寫一些小挑戰來學習有關該語言的基本細節。由於不可變性,我認爲我有一個問題。F#不變性,純功能和副作用

場景: 我必須在控制檯中讀取高度線,每行包含一個整數。該整數代表山的大小。 閱讀輸入後,我需要寫出最高山脈的行數。 如果給出的指數是最高的山,那麼大小設置爲零,否則我鬆動。 重複該場景,直到所有的山都將其大小設置爲零。

下面的代碼我寫道:

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() = ...定義了一個函數。它的身體將在您每次打電話時執行。在這種情況下,身體有副作用,並且每次執行身體時都會執行副作用(從標準輸入讀取)。所以這不是你的問題。

readAllMountainsData被定義爲包含七座山的數據的列表。每座山都有自己的高度(因爲每座山都會調用readLineInt())。此列表僅計算一次,之後不會更改。它不會在每次使用readAllMountainsData時重新計算,因爲它是一個變量,而不是函數(儘管名稱可能會有其他建議)。這似乎是非常明智的,因爲每次重讀山區數據都沒有意義。

mutable關鍵字添加到定義允許您重新分配變量。也就是說,它允許您稍後在程序中編寫readAllMountainsData <- someNewValue以更改變量的值。既然你從來沒有這樣做過,沒有什麼改變。

你的程序無限循環的原因是mainLoop總是再次調用自己。它沒有退出條件。因此,爲了解決這個問題,你應該決定你想多久循環一次/在哪種情況下你想退出,然後相應地實現這個邏輯。


在你的編輯你澄清,說你想重新閱讀你的價值觀,所以你只需給它一個參數列表(let readAllMountainsData() = ...),使readAllMountainsData一個函數,然後把它作爲一個功能。這樣你就可以在每次迭代中獲得新的數據,但是除非添加退出條件,否則循環仍然是無限的。

+0

主循環調用自身,因爲我想要重複這個步驟直到結束(所有的山峯高度都設置爲0)。我嘗試通過添加()來創建一個帶有readAllMountainsData的函數,但它沒有改變任何東西。 –

+0

@ CedricRoyer-Bertrand如果你想自己調用,直到所有高度爲零,那麼這個條件需要在代碼中。目前你永遠稱自己,直到高度爲零。 – sepp2k

+0

好的,你發現了這個錯誤,事實上readAllMountainsData不是一個函數。我在之前的嘗試中犯了一個錯誤。我已經添加了條件停止在8.謝謝你的解釋也可變。我接受你的文章作爲答案。再次感謝。 –