不能在序列表达式中使用try / with块。怎么绕过它?

时间:2014-02-13 23:29:38

标签: .net f#

考虑一下

Pentagonal numbers are generated by the formula, Pn=n(3n−1)/2.

我选择在F#中创建一系列五角形数字:

let pentagonalSeq = { 1..Int32.MaxValue } |> Seq.map (fun n -> n*(3*n-1)/2)

到目前为止一切顺利。在大多数情况下,我只想计算几个小整数五边形数。但有时我希望获得所有Int32五角形数字。我以为可以继续计算它们,直到我最终得到OverflowException(我使用的是检查算术)。问题是F#对我的想法不是特别高兴,大喊那个

'try/with' cannot be used inside sequence expressions

让这位年轻女士满意的最佳方法是什么?

假设我要创建一个int32_pentagonalSeq

  1. 使用pentagonalSeq
  2. 不会产生任何额外的计算,试图预测下一个项目是否可能不会导致溢出。
  3. 由于

3 个答案:

答案 0 :(得分:4)

我认为Gene的答案可能就是要走的路!但是如果你想使用序列表达式迭代你已经拥有的序列的元素,你可以写下这样的东西:

let takeWhileNonException (input:seq<_>) = seq { 
  use ps = input.GetEnumerator()
  while (try ps.MoveNext() with _ -> false) do 
    yield ps.Current }

可悲的是,你不能只用for .. yield!包装try循环或with语句,因为(如你所说),序列表达式不支持异常处理程序。但是,您可以使用底层迭代器并将MoveNext调用包装在异常处理程序中(因为这是一个普通表达式)并在第一次操作失败时返回false

因此,要获得序列的最后一个数字,您现在可以写:

pentagonalSeq
|> takeWhileNonException
|> Seq.last

答案 1 :(得分:2)

你可以这样做吗?

let pentagonal n = 
   try
      Some(n*(3*n-1)/2)
   with
     | ex -> None

let x = { 1.. Int32.MaxValue } |> Seq.map pentagonal

答案 2 :(得分:2)

您可以使用Seq.unfold算法使用生成器函数代替序列理解而不是checked,就像下面的代码段一样:

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中看到什么是最后的五角形整数可以用这个公式计算而没有溢出

pentagonalSeq |> Seq.last;;
val it : int = 1073731660

显然这不是最大五边形Int32,顺便说一下,2147438935.但是,要计算1073731660和2147438935之间的五边形数字,您需要在int数字字段之外操作。从某种意义上说,这更容易实现您的初始目标,因为它根本不需要检查算术和try-with机制:

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