2009-10-13 99 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)