F-sharp (f#) untyped Infinity
-
21-09-2019 - |
سؤال
أتساءل لماذا لا يدعم F-Sharp Infinity.
هذا من شأنه أن يعمل في روبي (ولكن ليس في 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 (قيمة مزدوجة) على. $ fsi_0045.main@() توقف بسبب الخطأ
تحرير: يبدو أن هذا يعمل بالتكرار:
let numbers n = Seq.initInfinite (fun i -> i+1) |> Seq.take(n)
المحلول
بادئ ذي بدء ، فإن قوائم F# ليست كسول ، (لست متأكدًا من قوائم روبي كسول) ، لذلك حتى مع وجود فكرة عامة عن اللانهاية ، لا يمكن أن يعمل مثالك الأول أبدًا.
ثانياً ، لا توجد قيمة اللانهاية في int32. فقط maxvalue. هناك اللانهاية الإيجابية والسلبية في ضعف رغم ذلك.
تجميعها ، هذا يعمل:
let numbers n = seq { 1. .. 1./0. } |> Seq.take(n)
أشعر بأن seq.initinfinite هو الخيار الأفضل لك. الرمز أعلاه يبدو غريبا بالنسبة لي. (أو على الأقل استخدم double.positiveInfinity بدلاً من 1./0.)
للوهلة الأولى ، سيكون هناك خيار رائع أن يكون في اللغة مشغلًا لا حصر له مثل في Haskell: Seq {1 ..} المشكلة هي أنه سيعمل فقط مع SEQ ، لذلك أعتقد أن العمل الإضافي لدعم مشغلي Postfix هو لا يستحق ذلك لهذه الميزة وحدها.
خلاصة القول: في رأيي ، استخدم seq.initinfinite.
نصائح أخرى
أعتقد أن ما يلي هو الحل الأفضل للنطاقات اللانهائية في 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)