从Console.In读取函数返回以前的值 [英] Function reading from Console.In returns previous values

查看:71
本文介绍了从Console.In读取函数返回以前的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了学习F#,我正在尝试解决Codingame难题 The Descent

In order to learn F# I'm trying to solve the Codingame puzzle The Descent

  • 从Console.In.ReadLine()中读取8个数字
  • 应打印编号最高的索引
  • 重复8次

下面的代码可以在第一次运行时使用,但是对于不同的输入,在第一次循环后似乎可以给出完全相同的结果.
使用数组而不是从控制台读取在数组中运行Interactive中的idxWithHighestValue函数可以得到所需的结果.

Below code works for the first run, but appears to give the exact same result after the first loop for different inputs.
Running the idxWithHighestValue function in Interactive with an array instead of reading from console gives the desired results.

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

Expected behavior:
[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

Actual behavior:
[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函数有问题吗?

Is there something wrong with my readEightInputs function?

推荐答案

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

The problem is that highestMountain is just an int value, but you want it to be a function that reads console inputs and returns an int i.e. its type signature should be unit -> int instead of just int. Simply adding () (unit) to the declaration makes it a function that can be called—not just a value to be calculated once. Then you can call that function in your loop:

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#而言,其值永远不会改变.使其成为函数意味着您可以根据需要多次调用它,以获取不同的输入.

In your example, the code in highestMountain is only evaluated once to get its final int value and there's no need to evaluate it again; as far as F# is concerned its value could never change. Making it a function means you can call it as many times as you need to get different inputs.

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

Here's one way to refactor this code by extracting generally useful functions:

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

不是将所有功能嵌套在全功能中,而是将它们提取为通常有用的顶级功能并将其通过管道传输;而全功能highestMountain消失了.在读取控制台行并将其转换为int之间也存在关注点分离.如果您仍然想要该高级功能,现在可以将其构造为其他功能的组成:

Instead of nesting all the functions in an omni-function, this extracts them as generally useful, top-level functions and pipes them together; and the omni-function highestMountain is gone. There's also a separation of concerns between reading console lines and converting them to ints. If you still wanted that high-level function, it's now possible to construct it as a composition of your other functions:

// int -> int
let highestMountain = readLines >> Seq.map int >> maxValueIndex

现在这是一个函数,该函数接受许多(要读取的山脉)并返回最大的索引,称为printfn "%i" (highestMountain 8).请注意,尽管highestMountain定义没有显式的args,但它是一个 函数,因为它是通过>>运算符由其他函数组成的.它的参数与第一个函数readLines相同,其返回类型与最后一个函数maxValueIndex相同.之所以有效,是因为中间函数(咖喱函数)Seq.map intreadLines的输出和maxValueIndex的输入兼容.

This is now a function that takes a number (of mountains to read in) and returns the index of the largest one, called like printfn "%i" (highestMountain 8). Note that while the highestMountain definition has no explicit args, it is a function because it's a composition of other functions via >> operator. Its arguments are the same as its first function readLines, and its return type is that of its final function maxValueIndex. This works because the middle (curried) function Seq.map int is compatible with the output of readLines and the input of maxValueIndex.

这篇关于从Console.In读取函数返回以前的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆