2012-09-23 21 views
5

मैं एक टाइप किए गए सार वाक्यविन्यास पेड़ डेटाटाइप लिखने की कोशिश कर रहा हूं जो फ़ंक्शन एप्लिकेशन का प्रतिनिधित्व कर सकता है। मैं इस समस्या को गलत तरीके से आ रहा हूँ -फ़ंक्शन एप्लिकेशन के साथ टाइप किए गए अमूर्त वाक्यविन्यास पेड़

अब तक मैं

type Expr<'a> = 
    | Constant of 'a 
    | Application of Expr<'b -> 'a> * Expr<'b> // error: The type parameter 'b' is not defined 

मुझे नहीं लगता कि एफ # में एक तरह से जैसे कि अंतिम पंक्ति पर 'सभी ख के लिए' कुछ लिखने के लिए है है?

उत्तर

10

सामान्य रूप से, एफ # प्रकार प्रणाली आपके टाइप में एक टाइप किए गए अमूर्त वाक्यविन्यास पेड़ को परिभाषित करने के लिए पर्याप्त नहीं है (सीधे)। यह generalized algebraic data types (GADTs) का उपयोग करके किया जा सकता है जो F # में समर्थित नहीं हैं (हालांकि वे हास्केल और ओकैमल में उपलब्ध हैं)। एफ # में यह अच्छा लगेगा, लेकिन मुझे लगता है कि यह भाषा को थोड़ा और जटिल बनाता है।

तकनीकी रूप से बोलते हुए, संकलक शिकायत कर रहा है क्योंकि प्रकार परिवर्तनीय 'b परिभाषित नहीं किया गया है। लेकिन निश्चित रूप से, यदि आप इसे परिभाषित करते हैं, तो आपको Expr<'a, 'b> टाइप करें जिसका एक अलग अर्थ है।

आप एफ # में यह व्यक्त करना चाहते थे, तो आप इंटरफेस के आधार पर (एक अंतरफलक सामान्य विधि है, जो आप exists 'b तरह बाधा व्यक्त करने के लिए एक रास्ता दे तुम यहाँ की जरूरत है जो हो सकता है) एक तरीके का उपयोग करना होगा। यह शायद बहुत जल्द ही बहुत बदसूरत हो जाएगा, तो मुझे नहीं लगता कि यह एक अच्छा तरीका है, लेकिन यह कुछ इस तरह दिखेगा:

:

// Represents an application that returns 'a but consists 
// of an argument 'b and a function 'b -> 'a 
type IApplication<'a> = 
    abstract Appl<'b> : Expr<'b -> 'a> * Expr<'b> -> unit 

and Expr<'a> = 
    // Constant just stores a value... 
    | Constant of 'a 
    // An application is something that we can call with an 
    // implementation (handler). The function then calls the 
    // 'Appl' method of the handler we provide. As this method 
    // is generic, it will be called with an appropriate type 
    // argument 'b that represents the type of the argument. 
    | Application of (IApplication<'a> -> unit) 

(fun (n:int) -> string n) 42 की अभिव्यक्ति पेड़ का प्रतिनिधित्व करने के लिए, आप की तरह कुछ लिख सकता है

let expr = 
    Application(fun appl -> 
    appl.Appl(Constant(fun (n:int) -> string n), 
       Constant(42))) 

एक समारोह अभिव्यक्ति का मूल्यांकन करने के इस तरह लिखा जा सकता है:

let rec eval<'T> : Expr<'T> -> 'T = function 
    | Constant(v) -> v // Just return the constant 
    | Application(f) -> 
     // We use a bit of dirty mutable state (to keep types simpler for now) 
     let res = ref None 
     // Call the function with a 'handler' that evaluates function application 
     f { new IApplication<'T> with 
      member x.Appl<'A>(efunc : Expr<'A -> 'T>, earg : Expr<'A>) = 
       // Here we get function 'efunc' and argument 'earg' 
       // The type 'A is the type of the argument (which can be 
       // anything, depending on the created AST) 
       let f = eval<'A -> 'T> efunc 
       let a = eval<'A> earg 
       res := Some <| (f a) } 
     res.Value.Value 

जैसा कि मैंने कहा, यह एक सा वास्तव में चरम समाधान नहीं है, तो मैं मुझे नहीं लगता है वास्तव में इसका उपयोग करने के लिए टी एक अच्छा विचार है। मुझे लगता है कि ऐसा करने का एफ # तरीका अवांछित Expr प्रकार का उपयोग करना होगा। क्या आप अपनी परियोजना के समग्र लक्ष्य के बारे में कुछ और लिख सकते हैं (शायद एक और अच्छा दृष्टिकोण है)?

+0

एक स्पष्ट और पूरी तरह से स्पष्टीकरण, धन्यवाद! मैं देखूंगा कि मैं स्पष्ट रूप से समझा सकता हूं कि मैं क्या हासिल करने की कोशिश कर रहा हूं, लेकिन औसत समय में टाइप किए गए विकल्प को खोलने के लिए धन्यवाद। – TimC

+0

@TimC मदद करने के लिए खुशी हुई। मुझे लगता है कि यह दृष्टिकोण तब तक काम करेगा जब तक आपको _existential प्रकारों को अनुकरण करने की आवश्यकता हो। यदि आपको वास्तविक जीएडीटी की आवश्यकता है (जहां एक प्रकार का मामला अलग-अलग मामलों के लिए अलग होता है - यानी 'लैम्ब्डा' कुछ प्रकार का होगा 'एक्सप्र <'a ->' बी> ') तो मुझे नहीं लगता कि आप आसानी से कामकाज ढूंढ पाएंगे । –

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