2009-10-13 86 views
3

我想知道为什么F-Sharp不支持无限。F-Sharp(F#)无类型无限

这将在Ruby中工作(但不是在F#):

let numbers n = [1 .. 1/0] |> Seq.take(n) 

- > System.DivideByZeroException:试图除以零。

我可以在很多复杂的方式写相同的功能:

let numbers n = 1 |> Seq.unfold (fun i -> Some (i, i + 1)) |> Seq.take(n) 

- >工作

但是我认为,第一个会更清晰。 我找不到在F#中使用动态类型无限的简单方法。 有无穷的关键字,但它是浮动:

let a = Math.bigint +infinity;; 

System.OverflowException:BigInteger的不能代表无穷大。 在System.Numerics.BigInteger..ctor(Double值) 在$ @ FSI_0045.main() 停止由于错误


编辑:还这似乎在重复的工作:

let numbers n = Seq.initInfinite (fun i -> i+1) |> Seq.take(n) 
+0

它是在做整数还是浮点算术?这两者有无穷无尽的概念大不相同。 – 2009-10-13 08:07:13

+0

这在Ruby中不起作用。 Infinity在Ruby中也是一个浮点值,因此您需要进行浮点除法 - 1..1.0/0。 – Chuck 2009-10-13 08:12:01

+0

在这个特定的情况下,让数字n = seq {1..n}'可能是最简单的... – 2009-10-13 08:46:09

回答

8

首先,F#列表不是懒惰的(我不确定Ruby列表是懒惰的),所以即使使用无穷大的一般概念,您的第一个示例也无法工作。

其次,Int32中没有无穷大值。只有MaxValue。尽管Double有一个正面和负面的无穷大。

将其组合在一起,这个工程:

let numbers n = seq { 1. .. 1./0. } |> Seq.take(n) 

我觉得然而Seq.initInfinite是您最佳的选择。上面的代码对我来说看起来很奇怪。 (或者至少使用Double.PositiveInfinity而不是1./0)

乍一看,在语言中有一个很好的选择是像haskell那样的无限范围运算符:seq {1 ..}问题是它只能用于seq,所以我认为支持postfix运算符的额外工作并不值得这个功能。底线:在我看来,使用Seq.initInfinite。

+1

由于Seq.initInfinite基于Int32,因此,为了任何实际目的,它必须等同于'seq {1 .. System.Int32.MaxValue}'。使用这种构造,而不是愚蠢地认为任何无损伤实际上都涉及到。我会建议,而不是。 - 或者是展开的方法 - 当处理bigint ... – 2009-10-13 09:42:13

+0

@Johan:我觉得Seq.initInfinite在类型推理中效果更好 - 所产生的seq的类型应该被自动推断,而使用{1..Int32.MaxValue}你需要一个不断的呼叫。所以这可能是对原始问题的更接近的解决方案。但的确,initInfinite中的无限是一个误称。 – 2009-10-13 11:57:38

3

我认为以下是F#中无限范围的最佳解决方案;通过标记函数inline,我们做得比“动态类型无穷大”更好,我们得到了结构类型化的无限范围(与int32,int64,bigint,...一起使用,它有一个静态成员+,它带有两个自己类型的参数,返回它自己的类型的值):

let inline infiniteRange start skip = 
    seq { 
     let n = ref start 
     while true do 
      yield n.contents 
      n.contents <- n.contents + skip 
    } 

//val inline infiniteRange : 
// ^a -> ^b -> seq< ^a> 
// when (^a or ^b) : (static member (+) : ^a * ^b -> ^a)