मैं बस FromInt32
को संबोधित करूंगा। एक आदर्श दुनिया में, हम यह बस के रूप में
let inline FromInt32 i =
((^t or int) : (static member op_Explicit : int -> ^t) i)
जो स्थिर बाधाओं का उपयोग सुनिश्चित करने के लिए है कि हम int
से एक स्पष्ट रूपांतरण इनलाइन सकता है के रूप में परिभाषित कर सकते हैं। दुर्भाग्यवश, इसके साथ दो समस्याएं हैं। पहला यह है कि वाक्यविन्यास अमान्य है - आपके पास सदस्य की बाधा के "स्थैतिक-टाइपर्स" हिस्से में एक ठोस प्रकार (जैसे int
) नहीं हो सकता है। हम इस के चारों ओर एक सहायक समारोह
let inline cvt i = ((^t or ^u) : (static member op_Explicit : ^u -> ^t) i)
let inline FromInt32 (i:int) = cvt i
को परिभाषित इन कार्यों inlined कर रहे हैं दोनों के बाद से काम कर सकते हैं, इस पहले प्रयास की तुलना में किसी भी कम कुशल नहीं है, यह सिर्फ wordier है।
यहाँ है जहाँ हम दूसरी समस्या में पड़: यह असली op_Explicit
परिभाषाओं (या op_Implicit
है, जो विशेष रूप से संकलक द्वारा इलाज किया जाता है ताकि यह op_Explicit
द्वारा सम्मिलित किया जाता है) के लिए काम करेंगे। तो (10G : bigint)
को रेखांकित किया जाएगा जैसे आपने System.Numerics.BigInt.op_Implicit 10
लिखा था, जो कि हम जितना सक्षम हो उतना कुशल है। हालांकि, एफ # भी कई आदिम प्रकार के लिए op_Explicit
(int
से float
, byte
, आदि के लिए रूपांतरण के लिए जैसे) simulates, और के बाद से FromInt32
की परिभाषा इन सदस्यों के अस्तित्व पर निर्भर करता है यह (है कि, (10G : float)
और यहां तक कि है कार्यावधि में असफल हो जायेगी (10G : int)
संकलित होगा लेकिन निष्पादित होने पर अपवाद फेंक देगा)। आदर्श रूप से एफ # का भविष्य संस्करण इसे काम करने में सक्षम बनाता है, लेकिन एफ # 2.0 के रूप में, हमें एक कामकाज के साथ आने की आवश्यकता होगी।
यह अच्छा होगा यदि हम करने के लिए कैसे एफ # कोर पुस्तकालय इस तरह की समस्या है, जो विशेष आवरण गर्भित ऑपरेटरों के सभी की आवश्यकता होगी, लेकिन सब कुछ में परिणाम होगा संभालती एक समान दृष्टिकोण इस्तेमाल कर सकते हैं हो सकता है सही दक्षता के साथ inlined जा रहा है:
let inline FromInt32 (i : int) : ^t =
cvt i
when ^t : int = int i
when ^t : float = float i
when ^t : byte = byte i
...
हालांकि, एफ # संकलक एक "Static optimization conditionals are only for use within the F# library"
संदेश के साथ इस को खारिज कर दिया (और गुप्त --compiling-fslib
ध्वज के साथ संकलन केवल बातें बदतर बना देता है :))।
इसके बजाए, हमें रनटाइम पर समान कुछ प्राप्त करने के लिए संकेत के कुछ अतिरिक्त परतों का उपयोग करने की आवश्यकता है। सबसे पहले, हम एक सामान्य प्रकार का एक स्थिर सदस्य का उपयोग करके रूपांतरण कार्यों के लिए प्रकार की एक क्रम मानचित्रण पैदा हो जाएगी:
type IntConverterDynamicImplTable<'t>() =
static let result : int -> 't =
let ty = typeof< 't> //'
if ty.Equals(typeof<sbyte>) then sbyte |> box |> unbox
elif ty.Equals(typeof<int16>) then int16 |> box |> unbox
elif ty.Equals(typeof<int32>) then int |> box |> unbox
elif ty.Equals(typeof<int64>) then int64 |> box |> unbox
elif ty.Equals(typeof<nativeint>) then nativeint |> box |> unbox
elif ty.Equals(typeof<byte>) then byte |> box |> unbox
elif ty.Equals(typeof<uint16>) then uint16 |> box |> unbox
elif ty.Equals(typeof<char>) then char |> box |> unbox
elif ty.Equals(typeof<uint32>) then uint32 |> box |> unbox
elif ty.Equals(typeof<uint64>) then uint64 |> box |> unbox
elif ty.Equals(typeof<unativeint>) then unativeint |> box |> unbox
elif ty.Equals(typeof<decimal>) then decimal |> box |> unbox
elif ty.Equals(typeof<float>) then float |> box |> unbox
elif ty.Equals(typeof<float32>) then float32 |> box |> unbox
else
let m =
try ty.GetMethod("op_Implicit", [| typeof<int> |])
with _ -> ty.GetMethod("op_Explicit", [| typeof<int> |])
let del =
System.Delegate.CreateDelegate(typeof<System.Func<int,'t>>, m)
:?> System.Func<int,'t>
del.Invoke |> box |> unbox
static member Result = result
यह है कि हम क्या पिछले प्रयास में स्थिर अनुकूलन सशर्त, साथ प्राप्त करने के लिए कोशिश कर रहे थे के समान है , लेकिन यह संकलन समय पर मूल्यांकन किए जा रहे सब कुछ के बजाय रनटाइम को स्थगित कर दिया गया है।अब हम सिर्फ इस प्रकार का उपयोग करने के लिए कुछ मान निर्धारित करने की जरूरत है:
let inline constrain< ^t, ^u when (^t or ^u) : (static member op_Explicit : ^t -> ^u)>() =()
let inline FromInt32 i : ^t =
constrain<int, ^t>()
IntConverterDynamicImplTable.Result i
यहाँ, constrain
समारोह बस सुनिश्चित करें कि FromInt32
केवल जहां पूर्णांक से एक स्पष्ट रूपांतरण वहाँ प्रकार के लिए लागू किया जा सकता है बनाने के लिए या एक प्रयोग किया जाता है (संकलक द्वारा अनुकरण)। FromInt32
के भीतर constrain()
पर वास्तविक कॉल संकलन के दौरान अनुकूलित हो जाना चाहिए।
इस दृष्टिकोण के साथ
, (10G : bigint)
IntConverterDynamicImplTable<bigint>.Result 10
की तरह कुछ करने के लिए संकलित होगा मिलता है, और IntConverterDynamicTable<bigint>.Result
(System.Func<int,bigint>(bigint.op_Implicit)).Invoke
के लिए एक मूल्य के बराबर होगा (लेकिन संचित, ताकि प्रतिनिधि केवल एक बार बनाई गई है)। इसी प्रकार, (10G : int64)
IntConverterDynamicImplTable<int64>.Result 10
पर संकलित होगा, और IntConverterDynamicTable<int64>.Result
में रूपांतरण फ़ंक्शन (int64 : int -> int64)
के समतुल्य मूल्य होगा, इसलिए कुछ विधि कॉल के ओवरहेड हैं, लेकिन समग्र प्रदर्शन बहुत अच्छा होना चाहिए।
संपादित
हालांकि, अगर आप सिर्फ FromInt32
और FromInt64
समय देने के लिए की एक भोली कार्यान्वयन से अधिक कुशल कुछ के लिए देख रहे हैं हे (एन), यहाँ एक संस्करण है जो अभी भी अपेक्षाकृत सरल और केवल है लेता हे (लॉग एन) समय:
module SymmetricOps =
let inline (~-) (x:'a) : 'a = -x
let inline (+) (x:'a) (y:'a) : 'a = x + y
let inline (-) (x:'a) (y:'a) : 'a = x - y
let inline (*) (x:'a) (y:'a) : 'a = x * y
let inline (/) (x:'a) (y:'a) : 'a = x/y
let inline (%) (x:'a) (y:'a) : 'a = x % y
module NumericLiteralG =
open SymmetricOps
let inline FromOne() = LanguagePrimitives.GenericOne
let inline FromZero() = LanguagePrimitives.GenericZero
let rec compute zero one two (/) (%) Two (+) (-) (*) pow2 rest n =
if n = zero then rest
else
let rest' =
let nmod2 = n % two
if nmod2 = zero then rest
elif nmod2 = one then rest + pow2
else rest - pow2
compute zero one two (/) (%) Two (+) (-) (*) (Two * pow2) rest' (n/two)
let inline FromInt32 i = compute 0 1 2 (/) (%) (FromOne() + FromOne()) (+) (-) (*) (FromOne()) (FromZero()) i
let inline FromInt64 i = compute 0L 1L 2L (/) (%) (FromOne() + FromOne()) (+) (-) (*) (FromOne()) (FromZero()) i
वाह। महान स्पष्टीकरण के लिए धन्यवाद। – Daniel
इस पल के लिए अनुदान कि कोई भी प्राणघातक इसे लागू करने की संभावना नहीं है, क्या मनमाना सामान्य संख्या व्यक्त करने का एक आसान तरीका है? 'जेनेरिकझेरो' और 'जेनेरिकऑन' दिए गए हैं, लेकिन 'जेनेरिकएन' के बारे में क्या? जेनेरिक न्यूमेरिक ऑपरेशंस के लिए यह आवश्यक है ... और 'जेनेरिकऑन'/'शून्य' का उपयोग करके गणना करने के लिए अजीब है। – Daniel
@Daniel - ठीक है, मुझे लगता है कि यह इस बात पर निर्भर करता है कि आपको कितना कुशल होना चाहिए। आपके प्रश्न में इस्तेमाल किए गए 'FromInt32' के अधिक सरल दृष्टिकोण के साथ कुछ भी गलत नहीं है, यह सिर्फ इतना है कि इसके परिणामस्वरूप अधिक ओवरहेड होगा। – kvb