来自OO背景,我无法解决如何在尝试避免变异时解决FP的简单问题。
let mutable run = true
let player1List = ["he"; "ho"; "ha"]
let addValue lst value =
value :: lst
while run do
let input = Console.ReadLine()
addValue player1List input |> printfn "%A"
if player1List.Length > 5 then
run <- false
printfn "all done" // daz never gunna happen
我知道在某些情况下使用突变是可以的,但我正在努力训练自己避免突变作为默认值。有了这个说,有人可以告诉我一个上面没有使用F#突变的例子吗?
最终结果应该是player1List继续增长,直到项目的长度为6,然后退出并打印所有已完成&#39;
答案 0 :(得分:7)
最简单的方法是使用递归
open System
let rec makelist l =
match l |> List.length with
|6 -> printfn "all done"; l
| _ -> makelist ((Console.ReadLine())::l)
makelist []
我还删除了一些addValue
函数,因为在典型的F#代码中使用::
更加惯用。
您希望run = false
使用run <- false
的新F#编码器时,您的原始代码也存在常见问题。在F#中,=
总是用于比较。编译器确实警告过这个。
答案 1 :(得分:4)
正如其他人已经解释的那样,您可以使用递归重写命令式循环。这很有用,因为它是一种始终有效且对函数式编程非常重要的方法。
或者,F#提供了一组丰富的库函数来处理集合,这些函数实际上可以很好地表达您需要的逻辑。所以,你可以这样写:
let player1List = ["he"; "ho"; "ha"]
let player2List = Seq.initInfinite (fun _ -> Console.ReadLine())
let listOf6 = Seq.append player1List list2 |> Seq.take 6 |> List.ofSeq
这里的想法是你创建一个无限的懒惰序列,从控制台读取输入,将它附加在初始player1List
的末尾,然后取出前6个元素。
根据你的实际逻辑,你可能会有所不同,但好处是这可能更接近你想要实现的逻辑......
答案 2 :(得分:2)
在F#中,我们使用递归来进行循环。但是,如果您知道需要迭代多少次,可以使用F#List.fold来隐藏递归实现。
[1..6] |> List.fold (fun acc _ -> Console.ReadLine()::acc) []
答案 3 :(得分:1)
为了便于阅读,我会从匹配中删除管道,但在最后一个表达式中使用它以避免使用额外的括号:
open System
let rec makelist l =
match List.length l with
| 6 -> printfn "all done"; l
| _ -> Console.ReadLine()::l |> makelist
makelist []