2016-07-11 7 views
5

मैं कुछ महीनों के लिए एफ # के साथ काम कर रहा हूं लेकिन मेरी समस्या के लिए कोई संतोषजनक समाधान नहीं मिला। मैं मूल्यों के भेदभाव वाले संघ या इन मूल्यों पर संचालन के रूप में संचालन के उत्तराधिकार का वर्णन करना चाहता हूं। ओ> सूची रिकर्सिवली सभी कार्यों को लागू करके एक 'ओ प्रकार में परिवर्तित किया जा सकता है, और अभी भी रखें: इस तरह, मेरी प्रकार वैल <'एफ # जेनेरिक बाधा संघ प्रकार

type Val<'o> = 
    | Val of 'o 
    | Func1 of ('a->'o) * Val<'a> 
    | Func2 of ('a->'b->'o) * Val<'a> * Val<'b> 

प्रकार वैल < ओ> इस प्रकार परिभाषित किया गया है ' संचालन के

लेकिन अगर मैं वैल < 'ए,' बी, 'ओ> ​​का उपयोग नहीं करता हूं तो मैं जेनेरिक प्रकार' ए और 'बी और उनकी बाधाओं को परिभाषित नहीं कर सकता। तो मुझे क्या करना है, मैं उप-वैल सामान्य प्रकार है, जो मैं सामान्य रहना चाहते हैं परिभाषित करने के लिए है:

type Val<'a, 'b, 'o> = 
    | Val of 'o 
    | Func1 of ('a->'o) * Val<?, ?, 'a> 
    | Func2 of ('a->'b->'o) * Val<?, ?, 'a> * Val<?, ?, 'b> 

वहाँ किसी भी एफ # संरचना है कि इस समस्या के लिए अनुकूलित किया जा सकता है?

बहुत धन्यवाद

[संपादित करें]

मेरी समस्या आगे का वर्णन करने के लिए, मैं एक एफआरपी संरचना की विस्तृत प्रतिनिधित्व (लेकिन genericity समस्या पाने के लिए कोशिश कर रहा हूँ के लिए घटनाओं/संकेतों में ही है कि मूल्यों के लिए)।
प्रतिनिधित्व डेटाबेस भंडारण, के लिए प्रदर्शन और उपयोगकर्ता संपादित पाठ में अनुवाद किया या का मूल्यांकन एक परिणाम पाने के लिए या तो धारावाहिक हो सकता है:

"Func (x -> x²) (Val(3.4))" <--> representation <--> 11.56 
      | 
      user 

मैं एक प्रोटोटाइप काफी अच्छी तरह से काम कर रहे एक PrimitiveValue संघ प्रकार का उपयोग किया जाता है, और जेनेरिक obj[] -> obj कार्यों में रनटाइम पर संकलित स्ट्रिंग्स स्ट्रिंग्स, लेकिन मूल्यांकन जांच और कास्टिंग पर बहुत भारी है (विशेष रूप से क्योंकि मैं PrimitiveValue में सरणी और विकल्पों का भी उपयोग कर रहा हूं), इसलिए मैं एक और अधिक सुरुचिपूर्ण और दृढ़ता से टाइप किए गए समाधान की तलाश में था।

उत्तर

6

यहां मूल समस्या यह है कि एफ # आपको यह नहीं कहने देता है कि भेदभाव वाले संघ के मामले में 'a और 'b मामले में संग्रहीत डेटा के "पैरामीटर" हैं। कुछ अन्य भाषाएं इसका समर्थन करती हैं (इसे हास्केल में सामान्यीकृत बीजगणितीय डेटा प्रकार कहा जाता है), लेकिन भाषा को और अधिक जटिल बनाने का एक सामान्य व्यापार-बंद है।

आप वास्तव में इसे F # में अनुकरण कर सकते हैं, लेकिन यह बदसूरत है - इसलिए मैं इस तरह से जाने से पहले दो बार सोचूंगा। विचार यह है कि आप एक सामान्य विधि के साथ एक इंटरफेस को परिभाषित कर सकते हैं जो उचित प्रकार के तर्क 'a और 'b के साथ लागू हो जाता है।

type Val<'T> = 
    | Val of 'T 
    | Func of IFunc<'T> 

and IFunc<'T> = 
    abstract Invoke<'R> : IFuncOperation<'T, 'R> -> 'R 

and IFuncOperation<'T2, 'R> = 
    abstract Invoke<'T1> : ('T1 -> 'T2) * Val<'T1> -> 'R 

Func में लिपटे मूल्य IFuncOperation दिया जा सकता है और यह आपके 'a सामान्य विधि के प्रकार तर्क होने के साथ यह लागू करेगा - मेरे नामकरण में 'T1

let makeFunc f v = 
    Func({ new IFunc<_> with member x.Invoke(op) = op.Invoke(f, v) })  
let makeVal v = Val(v) 

let valString = makeFunc (fun n -> sprintf "Got: %d" n) (makeVal 42) 

अब, valString एक int -> string परिवर्तन Val<int> के लिए लागू प्रतिनिधित्व करता है:

आप मूल्यों यथोचित अच्छा के निर्माण कर सकते हैं।

कोड आप Func पर पैटर्न मिलान करने के लिए लिखने की ज़रूरत है, हालांकि बहुत बदसूरत है:

let rec eval<'T> (value:Val<'T>) : 'T = 
    match value with 
    | Val r -> r 
    | Func f -> 
     { new IFuncOperation<'T, 'T> with 
      member x.Invoke<'S>(f, value:Val<'S>) = f (eval<'S> value) } 
     |> f.Invoke 

eval valString 

मैं deedle के आंतरिक भागों में से कुछ में समान पैटर्न का इस्तेमाल किया है, लेकिन कोड में कभी नहीं भी पास हो सकता है कि उपयोगकर्ताओं को क्या अंत लिखने के लिए। मुझे लगता है कि यह कुछ बहुत ही छिपे हुए आंतरिक स्तर पर स्वीकार्य है, लेकिन मैं निश्चित रूप से इसे किसी ऐसे चीज़ में उपयोग करने से बचना चाहूंगा जिसे अक्सर कहा जाता है।

आपकी मूल समस्या क्या थी, इस पर निर्भर करता है कि संभवतः एक अच्छा तरीका है - आप एक भेदभाव वाले संघ PrimitiveValue को परिभाषित कर सकते हैं ताकि आपके गणना का उत्पादन करने वाले विभिन्न आदिम मूल्यों को पकड़ सकें, या आप इंटरफ़ेस का उपयोग करके केवल संचालन का प्रतिनिधित्व कर सकते हैं - लेकिन यह कहना मुश्किल है कि संदर्भ जानने के बिना आपके मामले में क्या बेहतर है।

+1

ध्यान दें कि आप 'यूनिट'-रिटर्निंग ऑपरेशंस को सक्षम करने के लिए दूसरा 'Invoke' अधिभार भी चाहते हैं। – kvb

+0

यह भी ध्यान दें कि 'IFuncOperation <_,_> 'में' वैल <_> 'के दूसरे एप्लिकेशन द्वारा' टी 1 -> 'टी 2' को लपेटने से आपको' अच्छी तरह से 'वैल <_>' की अच्छी संख्या में मनमाने ढंग से घुमावदार धैर्य के कार्यों को लागू करने में सक्षम बनाता है। – kvb

संबंधित मुद्दे