.net 不能在序列表达式内使用try/with块。如何避开它?
考虑一下.net 不能在序列表达式内使用try/with块。如何避开它?,.net,f#,.net,F#,考虑一下 Pentagonal numbers are generated by the formula, Pn=n(3n−1)/2. 我选择在F#中创建一个五边形数字序列: 到目前为止还不错。对于大多数情况,我只想计算几个小的整数五边形数。但有时我可能希望得到所有的Int32五边形数字。我在想,继续计算它们是可能的,直到我最终得到一个OverflowException(我使用的是checked算术)。问题是F#对我的想法不太满意,大喊大叫 'try/with' cannot be used
Pentagonal numbers are generated by the formula, Pn=n(3n−1)/2.
我选择在F#中创建一个五边形数字序列:
到目前为止还不错。对于大多数情况,我只想计算几个小的整数五边形数。但有时我可能希望得到所有的Int32
五边形数字。我在想,继续计算它们是可能的,直到我最终得到一个OverflowException
(我使用的是checked算术)。问题是F#对我的想法不太满意,大喊大叫
'try/with' cannot be used inside sequence expressions
让这位年轻女士满意的最好办法是什么
假设我想创建一个int32_pentagonalSeq
,它:
pentagonalSeq
谢谢你能做点像这样的事情吗
let pentagonal n =
try
Some(n*(3*n-1)/2)
with
| ex -> None
let x = { 1.. Int32.MaxValue } |> Seq.map pentagonal
您可以使用算术来代替序列理解与生成器函数一起使用,如下面的代码段所示:
open Checked
let generator n =
try
Some ((n*(3*n-1)/2), n+1)
with
| :? System.OverflowException -> None
let pentagonalSeq = Seq.unfold generator 1
现在,您可以在FSI中看到最后一个五角整数是什么,可以使用此公式计算,而不会出现溢出:
显然这不是最大的五边形Int32,顺便说一下,是2147438935。但是,要计算1073731660和2147438935之间的五边形数,您需要在int
numbers字段之外进行操作。从某种意义上说,这使得实现初始目标更加容易,因为它不需要检查算术和尝试使用机器:
let pentagonalSeq = Seq.unfold
(fun n -> let pentagonal = n*(3L*n-1L)/2L in
if pentagonal > (int64 System.Int32.MaxValue) then
None // Sequence is over
else
Some((int pentagonal), n+1L)) // Member and next state
1L // Initial state
再次检查FSI,我们可以看到现在它是一个真正的int
五边形数字序列,事实上:
pentagonalSeq |> Seq.last;;
val it : int = 2147438935
我认为吉恩的答案可能是正确的!但是,如果您想使用序列表达式来迭代已经存在的序列元素,您可以编写如下内容:
let takeWhileNonException (input:seq<_>) = seq {
use ps = input.GetEnumerator()
while (try ps.MoveNext() with _ -> false) do
yield ps.Current }
Gene,虽然你给出了一个非常有趣的答案,但它不仅在第1点上失败了,“利用了pentagonalSeq”,因为它在第2点上失败了:“不会产生任何额外的计算,试图预测下一个项目是否可能引发溢出。”@Ownedelysium:真的吗?(1) 我不使用pentagonalSeq
定义是有充分理由的-根据定义,它只允许得到少于一半的Int32
五角数,因此不能作为完整序列的基础;(2)涉及溢出并不是一个完全正确的方法(参见(1)了解结果),因此我根本不使用它们来实现第2点。建议的惯用方法产生完整的Int32
五边形序列,在我看来确实不是“双重失败”。托马斯的回答中引入的非常酷的takeWhileNonException
无法弥补pentagonalSeq
中的缺陷,它会过早溢出。可以通过将mapper函数更改为fun n->让nL=int64 n in int(nL*(3L*nL-1L)/2L)
来修复它。我承认这个问题有点不适定。我并不特别关心五边形溢出,我关心的是正确处理序列,而不是我自己的抛出异常。放松
pentagonalSeq |> Seq.last;;
val it : int = 2147438935
let takeWhileNonException (input:seq<_>) = seq {
use ps = input.GetEnumerator()
while (try ps.MoveNext() with _ -> false) do
yield ps.Current }
pentagonalSeq
|> takeWhileNonException
|> Seq.last