F# 序号:展开F中的解释#
我正试图通过使用F#懒洋洋地创建一个序列 序列定义如下: 序列的第n项 三角形数由,tn给出= ½n(n+1);所以前十个三角形 数字如下: 1,3,6,10,15,21,28,36,45,55, 以下是我到目前为止所做的,但似乎不起作用:F# 序号:展开F中的解释#,f#,seq.unfold,F#,Seq.unfold,我正试图通过使用F#懒洋洋地创建一个序列 序列定义如下: 序列的第n项 三角形数由,tn给出= ½n(n+1);所以前十个三角形 数字如下: 1,3,6,10,15,21,28,36,45,55, 以下是我到目前为止所做的,但似乎不起作用: let tri_seq = 1.0 |> Seq.unfold (fun x -> match x with
let tri_seq = 1.0 |> Seq.unfold (fun x -> match x with
| _ -> Some (x, 0.5*x*(x + 1.0)))
非常感谢您能帮助我了解unfold的工作原理。谢谢
编辑:我将第一个答案标记为正确,但它不起作用,但是我稍微修改了一下,它就起作用了
let tri_seq = 1.0 |> Seq.unfold (fun x -> Some (0.5 * x * (x + 1.0),x + 1.0))
首先,如果只有一个案例,为什么要使用
match
let tri_seq = 1.0 |> Seq.unfold (fun x -> Some (x, 0.5 * x * (x + 1.0)))
第二,什么“似乎不起作用”?您是否知道您生成了一个无限列表
/编辑:为了完整起见,这里有一个正确的解决方案,OP自己找到了,并将其作为评论发布:
let tri_seq =
1.0 |> Seq.unfold (fun x -> Some (0.5 * x * (x + 1.0), x + 1.0))
这里有一个替代方案:
let tri = seq {
let n = ref 1.0
let diff = ref 2.0
while true do
yield !n
n := !n + !diff
diff := !diff + 1.0
}
printfn "%A" (tri |> Seq.take 10 |> Seq.to_list)
Brian发布的代码的另一种替代方法是使用递归,而不是命令式“while”循环:
let tri =
let rec loop(n, diff) = seq {
yield n
yield! loop(n + diff, diff + 1.0) }
loop(1.0, 2.0)
printfn "%A" (tri |> Seq.take 10 |> Seq.to_list)
它的效率要低得多(因此您在这里必须小心一点……),但它是更惯用的函数式解决方案,因此可能更容易看到代码的作用。我知道这是一个非常古老的解决方案,但我不明白为什么在确定x*(x+1)是偶数并且确实可以被2整除的情况下使用float。 所以我只想用这个来代替(我知道差别不大,但至少你有一个int-seq):
(当然,除非你处理的是大量的数据…)我试过了,但序列只返回一个…>三;;valit:seq=seq[1.0;1.0;1.0;1.0;…]让tri_-seq=1.0 |>seq.unfold(乐趣x->Some(0.5*x*(x+1.0),x+1.0))是我所需要的。非常感谢。谢谢,但是我不知道“Seq{}”是什么意思,不是“yield”关键字,更别说“!”了。如果您能花点时间解释,我们将不胜感激!不是专家,但Seq{}的意思是让我从中得到一个序列。yield与C#相同,表示返回值并等待调用代码请求下一个值。产量is(我相信)与Seq.concat类似-将递归调用返回的Seq变平,并对每个元素进行一次让步。可以做一些努力,至少使
循环
具有尾部递归,否则这将无法扩展anywhere@pqnetF#编译器实际上可以很好地处理递归seq
表达式,所以这个模式工作得很好(不像C#中的foreach(x in y)产生x
,这会有问题)@TomasPetricek你是对的,函数实际上是一个尾部调用,因为序列是惰性的,loop
返回一个序列,然后作为当前序列的延续返回。如果屈服
和屈服代码>的顺序正好相反,这可能会有问题,但这样就可以进行优化
let tri_seq = 1 |> Seq.unfold (fun x -> Some (x * (x + 1) / 2 , x + 1))
tri_seq |> Seq.take 6 |> Seq.toList //[1; 3; 6; 10; 15; 21]