2017-07-27 23 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.谢谢你的解释也可变。我接受你的文章作为答案。再次感谢。 –