F#不变性,纯功能和副作用

Ced*_*and 2 f# immutability purely-functional

我是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()
Run Code Online (Sandbox Code Playgroud)

这段代码将无限循环,我相信这是因为

let readlineInt() = int(Console.In.ReadLine())
Run Code Online (Sandbox Code Playgroud)

是不可变的,所以值设置一次,之后永远不会再次停止读取该行.我尝试将'mutable'关键字用于

let mutable readAllMountainsData = [ for a in 0 .. 7 do yield readMountainData a ]
Run Code Online (Sandbox Code Playgroud)

但它并没有改变一件事.你有什么主意吗?

编辑: 我知道这段代码进入无限循环,因为在将主页循环添加到主循环后如下:

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()
Run Code Online (Sandbox Code Playgroud)

然后我在输出中有这个:

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...
Run Code Online (Sandbox Code Playgroud)

为什么我要重读这个值?因为值是由外部源提供的.所以工作流程如下:

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
Run Code Online (Sandbox Code Playgroud)

sep*_*p2k 6

let readlineInt () = ...定义一个函数.每次调用它时都会执行它的正文.在这种情况下,身体具有副作用,并且每次执行身体时都会执行副作用(从stdin读取).所以这不是你的问题.

readAllMountainsData被定义为包含七座山脉数据的列表.这些山脉中的每一座都有自己的高度(因为readLineInt()每座山都需要一次).此列表计算一次,之后不会更改.每次使用时都不会重新计算,readAllMountainsData因为它是变量,而不是函数(即使名称可能暗示其他情况).这似乎是非常明智的,因为每次重读山数据都没有意义.

mutable关键字添加到定义允许您重新分配变量.也就是说,它允许您readAllMountainsData <- someNewValue稍后在程序中写入以更改变量的值.既然你从未真正这样做过,那就没有任何改变

你的程序无限循环的原因是它mainLoop总是再次调用自己.它没有退出条件.因此,为了解决这个问题,您应该决定循环/在哪种情况下要退出的频率,然后相应地实现该逻辑.


在您的编辑中,您澄清了,您确实想要重新读取您的值,因此您只需要readAllMountainsData通过为其提供参数列表(let readAllMountainsData () = ...)然后将其作为函数调用来创建函数.这样,您将获得每次迭代的新数据,但除非您添加退出条件,否则循环仍将是无限的.