2012-05-14 12 views
5

मेरे कोड में, मेरे पास डेटाबेस पहुंच संदर्भ है जो CouchDB.ctx नामक प्राथमिक पढ़ने/लिखने के संचालन प्रदान करता है। मेरे आवेदन में विभिन्न मॉड्यूल तब उस वर्ग को अतिरिक्त कार्यक्षमता के साथ बढ़ाते हैं, जैसे Async.ctxओकैमल: हस्ताक्षर में टाइप बाधाएं

मैं Cache मॉड्यूल को कार्यान्वित कर रहा हूं जो Source मॉड्यूल के आसपास लपेटा गया है। Cache मॉड्यूल फ़ंक्शन एक संदर्भ तर्क लेते हैं और डेटाबेस में हेरफेर करते हैं। कुछ कॉल को संदर्भ के साथ Source मॉड्यूल पर अग्रेषित किया जाता है।

मैं इस की तर्ज पर एक functor निर्धारित करने होंगे:

module CouchDB = struct 
    class ctx = object 
    method get : string -> string option monad 
    method put : string -> string -> unit monad 
    end 
end 

module AsyncDB = struct 
    class ctx = object 
    inherit CouchDB.ctx 
    method delay : 'a. float -> (ctx -> 'a monad) -> 'a monad 
    end 
end 

module type SOURCE = sig 
    class ctx = #CouchDB.ctx (* <-- incorrect *) 
    type source 
    val get : source -> ctx -> string monad 
end 

module Cache = functor(S:SOURCE) -> struct 
    class ctx = S.ctx 
    type source = S.source 
    let get source ctx = 
    bind (ctx # get source) (function 
    | Some cache -> return cache 
    | None -> 
     bind (S.get source ctx) 
     (fun data -> bind (ctx # put source data) 
         (fun() -> return data)) 
end 

module SomeSource = struct 
    class ctx = AsyncDB.ctx 
    type source = string 
    let get s ctx = 
    ctx # async 300 (some_long_computation s) 
end 

module SomeCache = Cache(SomeSource) 

समस्या यह है कि मैं इस तथ्य है कि Source मॉड्यूल के द्वारा प्रयोग किया संदर्भ CouchDB.ctx की एक उप-प्रकार होना चाहिए व्यक्त नहीं कर सकते है। उपर्युक्त कोड त्रुटि देता है:

A type variable is unbound in this type declaration. 
In type #CouchDB.ctx as 'a the variable 'a is unbound 

मैं इस प्रकार की बाधा कैसे व्यक्त करूं?

+0

मैं आपके 'स्रोत' हस्ताक्षर के बारे में उत्सुक हूं। मेरे दिमाग में घोषणा 'मॉड्यूल प्रकार SOURCE = sig वर्ग ctx होना चाहिए: ऑब्जेक्ट को CouchDB.ctx end (* ... *) end' प्राप्त होता है; क्या आपको ऐसा करने की ज़रूरत नहीं है? –

उत्तर

5

[अप्रचलित ...

निकटतम आप प्राप्त कर सकते हैं के रूप में हस्ताक्षर को परिभाषित किया गया है

:

module type SOURCE = sig 
    type 'a ctx = 'a constraint 'a = #CouchDB.ctx 
    type source 
    val get : source -> 'a ctx -> string 
end 

लेकिन निश्चित रूप से, आप के रूप में अच्छी बस लिख सकते हैं:

module type SOURCE = sig 
    type source 
    val get : source -> #CouchDB.ctx -> string 
end 

संपादित करें : ध्यान दें कि ओकैम संरचनात्मक ऑब्जेक्ट्स के लिए टाइपिंग का उपयोग करता है। इसका मतलब है कि यहां तक ​​कि यदि आप चाहते थे, तो आप ऊपर की तुलना में और अधिक प्रतिबंधक नहीं प्राप्त कर सकते हैं। CouchDB.ctx या व्युत्पन्न वर्ग के उदाहरण होने के लिए get पर तर्कों को सीमित भी नहीं करता है - किसी ऑब्जेक्ट में (कम से कम) समान विधियां संगत होंगी। यहां तक ​​कि जब आप लिखते हैं

val get : source -> CouchDB.ctx -> string 

आप पारित कर सकते हैं किसी भी वस्तु एक ही तरीके का है। प्रकार CouchDB.ctx एक विशिष्ट संरचनात्मक ऑब्जेक्ट प्रकार का संक्षेप है जो समान नाम की कक्षा द्वारा उत्पन्न वस्तुओं से मेल खाता है। यह उन लोगों तक ही सीमित नहीं है। और बस सुनिश्चित करने के लिए: यह एक विशेषता माना जाता है।

======]

संपादित करें 2: विस्तारित उदाहरण के साथ, मैं अब आप क्या चाहते हैं और यही कारण है देखते हैं। दुर्भाग्यवश, यह ओकैमल में सीधे संभव नहीं है। आपको आंशिक रूप से प्रकारों की आवश्यकता होगी। अर्थात्, आपको

module type SOURCE = sig 
    type ctx < CouchDB.ctx 
    ... 
end 

यह ओकैमल में उपलब्ध नहीं है। हालांकि, अगर आप पास प्राप्त कर सकते हैं अगर आप हस्ताक्षर में एक स्पष्ट Upcast प्रदान करने के लिए तैयार हैं: ctx#put के लिए

module type SOURCE = sig 
    type ctx 
    val up : ctx -> CouchDB.ctx 
    type source = string 
    val get : source -> ctx -> string monad 
end 

फिर, Cache में, आप (S.up ctx)#get साथ ctx#get की घटनाओं को बदलने के लिए, और इसी तरह।

module Cache = functor (S:SOURCE) -> struct 
    type ctx = S.ctx 
    type source = S.source 
    let get source ctx = 
    bind ((S.up ctx)#get source) ... 
end 

module SomeSource = struct 
    type ctx = AsyncDB.ctx 
    let up ctx = (ctx : ctx :> CouchDB.ctx) 
    type source = string 
    let get s ctx = ... 
end 

module SomeCache = Cache (SomeSource) 

ध्यान दें कि मैं भी हस्ताक्षर SOURCE में type source = string पारदर्शी बनाया। इसके बिना, मैं नहीं देख सकता कि ctx#get sourceCache फ़ैक्टर में संभवतः टाइप-चेक कर सकता है।

+0

मुझे नहीं पता कि मैं अपनी स्थिति के साथ पहली परीक्षा कैसे कर सकता हूं (मेरे संदर्भ वर्ग में शून्य पैरामीटर हैं)। दूसरा संस्करण गलत है, क्योंकि यह 'Source.get' को' CouchDB.ctx' के किसी भी * सबक्लास को स्वीकार करने की अपेक्षा करेगा, जब वास्तव में यह केवल * एक * ('Async.ctx') स्वीकार करता है। –

+0

ठीक है, आप * Source.get' को प्रतिबंधित क्यों करना चाहते हैं? जहां तक ​​मैं देख सकता हूं, यह जरूरी नहीं है, और न ही यह कुछ भी खरीदता है (सभी सबटाइपिंग ओकैमल में पूरी तरह से संरचनात्मक है, भले ही आप कक्षा के नामों का उपयोग करें)। मैं ओकैम पर नाममात्र उपप्रकार के कुछ रूप को मजबूर करने की कोशिश नहीं करने की सिफारिश करता हूं, क्योंकि यह नहीं है कि भाषा कैसे काम करती है। ओकैमल नाममात्र पर संरचनात्मक टाइपिंग का समर्थन करता है, और सबटाइपिंग पर बहुलकता का समर्थन करता है। टाइपिंग जांच के लिए जरूरी है तो केवल बाध्य प्रकार। –

+0

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

1

जब तक मैं गलत समझ रहा हूँ कि तुम क्या करने के बाद तो इस चाल करना चाहिए रहे हैं:

module type SOURCE = sig 
    class ctx : CouchDB.ctx 
    type source 
    val get : source -> ctx -> string 
end 

class ctx : CouchDB.ctx एक class-specification है। OCaml डॉक्स उन्हें

This is the counterpart in signatures of class definitions. A class specification matches a class definition if they have the same type parameters and their types match.

का वर्णन वहाँ भी है इस

module type SOURCE = sig 
    class type ctx = CouchDB.ctx 
    type source 
    val get : source -> ctx -> string 
end 

जो आसानी से अलग है। पूर्व में मॉड्यूल में एक वास्तविक श्रेणी परिभाषा की आवश्यकता होती है जिसे बाद में कक्षा परिभाषा या क्लैस्स्टइप परिभाषा (यानी एक वर्ग प्रकार उपनाम) स्वीकार करता है।

+0

मैंने अपने प्रश्न को अद्यतन किया है ताकि मज़ेदार के उपयोग का एक उदाहरण शामिल हो सके, ताकि आप इसे संकलित भी कर सकें। आपके समाधानों ने 'SOURCE' हस्ताक्षर से मिलान करने से 'कुछ स्रोत' को रोका, क्योंकि वे 'ctx = async.ctx' को कक्षाओं या वर्ग प्रकारों के रूप में अनुमति नहीं देते हैं। –

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