F# 从Console.In读取函数返回以前的值

F# 从Console.In读取函数返回以前的值,f#,F#,为了学习F#我正试图解决密码问题 从Console.In.ReadLine()读取8个数字 应打印最高编号的索引 重复8次 下面的代码适用于第一次运行,但对于不同的输入,在第一次循环后似乎给出了完全相同的结果。 在与数组交互的情况下运行idxWithHighestValue函数,而不是从控制台读取,可以获得所需的结果 预期行为: [9,8,7,6,5,4,3,2]=>0 [0,8,7,6,5,4,3,2]=>1 实际行为: [9,8,7,6,5,4,3,2]=>0 [0,8,7,6,5,4,

为了学习F#我正试图解决密码问题

  • 从Console.In.ReadLine()读取8个数字
  • 应打印最高编号的索引
  • 重复8次
下面的代码适用于第一次运行,但对于不同的输入,在第一次循环后似乎给出了完全相同的结果。
在与数组交互的情况下运行idxWithHighestValue函数,而不是从控制台读取,可以获得所需的结果

预期行为:
[9,8,7,6,5,4,3,2]=>0
[0,8,7,6,5,4,3,2]=>1

实际行为:
[9,8,7,6,5,4,3,2]=>0
[0,8,7,6,5,4,3,2]=>0

open System

let highestMountain =
    let readEightInputs =
        let readlines n = Array.init n (fun _ -> Console.In.ReadLine() |> int)
        readlines 8
    let idxWithHighestValue list = 
        list
        |> Seq.mapi (fun i v -> i, v)
        |> Seq.maxBy snd
        |> fst
    idxWithHighestValue readEightInputs

(* game loop *)
while true do   
    (* Write an action using printfn *)
    (* To debug: Console.Error.WriteLine("Debug message") *)

    printfn "%i" highestMountain(* The index of the mountain to fire on. *)
    ()

我的readEightInputs函数有什么问题吗?

问题是,
最高峰
只是一个
int
值,但您希望它是一个读取控制台输入并返回
int
的函数,即它的类型签名应该是
unit->int
,而不是
int
。只需将
()
(单位)添加到声明中,它就成为了一个可以调用的函数,而不仅仅是一个要计算一次的值。然后可以在循环中调用该函数:

let highestMountain () =
    let readEightInputs =
        let readlines n = Array.init n (fun _ -> Console.In.ReadLine() |> int)
        readlines 8
    let idxWithHighestValue list = 
        list
        |> Seq.mapi (fun i v -> i, v)
        |> Seq.maxBy snd
        |> fst
    idxWithHighestValue readEightInputs

while true do
    let result = highestMountain()
    printfn "%i" result (* The index of the mountain to fire on. *)
    ()
在您的示例中,
highestMountain
中的代码只计算一次,以获得其最终的
int
值,无需再次计算;就F#而言,它的价值永远不会改变。使它成为函数意味着您可以根据需要多次调用它以获得不同的输入

这里有一种通过提取通常有用的函数来重构代码的方法:

let readLines count = // int -> string[]
  [| for _ in 1 .. count -> Console.ReadLine() |]
let maxValueIndex source = // seq<'a> -> int
  source
  |> Seq.mapi (fun i v -> i, v)
  |> Seq.maxBy snd
  |> fst
while true do
  let highMountainIdx = readLines 8 |> Seq.map int |> maxValueIndex
  printfn "%i" highMountainIdx
  ()
// int -> int
let highestMountain = readLines >> Seq.map int >> maxValueIndex

现在,这是一个函数,它获取大量(要读取的山脉)并返回最大山脉的索引,称为like
printfn“%i”(最高山8)
。请注意,
highestMountain
定义没有明确的参数,但它是一个函数,因为它是通过
运算符由其他函数组成的。它的参数与第一个函数
readLines
相同,返回类型与最后一个函数
maxValueIndex
相同。这是因为中间(curried)函数
Seq.map int
readLines
的输出和
maxValueIndex
的输入兼容
Taylor Wood已经指出
highestMountain
只是一个整数值,而不是一个函数。我只想提一下,您会问“我的readEightInputs函数有什么问题吗?”,但事实上,在您向我们展示的代码中,
readEightInputs
也是一个值,而不是一个函数。在F#中,这是一个值:

let name = (series of expressions)
这是一个函数:

let name parameter = (series of expressions)
如果名称后面至少有一个参数,即使该参数是“单位”值
()
,那么它是一个函数,=字符后面的一系列表达式将在每次调用该函数时求值。如果没有参数,则该值只计算一次。(顺便说一句,“unit”值
()
非常有用。请将此值视为空元组:空元组只有一个可能的值,因此该类型称为
unit
,因为它只能有一个)


我还要提到一件事:你的
readeightinput
值,即使你把它变成了一个函数,看起来也有点傻。为什么不直接使用
readlines
函数呢?
readlines
函数是一个好的、有用的函数。您可以将该行写成
idxWithHighestValue(readlines 8)
,而不是
idxWithHighestValue(readlines 8)
。瞧:现在如果你在以后的练习中不得不读十行,你可以调用
readlines10
。代码重用是一件好事。

aha,没有预期的错误。Thx:)Thx了解更多信息。我在这里真正学到了新东西:)我读过关于这个单元的书,但直到现在我才真正了解它。Thx:)注册readEightLines:你可能是对的,我只是在试验我应该把它推多远