2011-07-20 9 views
5

मैंने एक साधारण ओकैमल समस्या में ठोकर खाई है, लेकिन मुझे एक सुरुचिपूर्ण समाधान नहीं मिल रहा है। मैं उन मज़ेदारों के साथ काम कर रहा हूं जो अपेक्षाकृत सरल मॉड्यूल पर लागू होते हैं (वे आमतौर पर उस प्रकार पर एक प्रकार और कुछ कार्यों को परिभाषित करते हैं) और अतिरिक्त जटिल कार्यों, प्रकारों और मॉड्यूल जोड़कर उन सरल मॉड्यूल का विस्तार करते हैं। एक सरलीकृत संस्करण होगा:मॉड्यूल और रिकॉर्ड फ़ील्ड्स

module type SIMPLE = sig 
    type t 
    val to_string : t -> string 
    val of_string : string -> t 
end 

module Complex = functor (S:SIMPLE) -> struct 
    include S 
    let write db id t = db # write id (S.to_string t) 
    let read db id = db # read id |> BatOption.map S.of_string 
end 

क्योंकि इसके सभी कार्यक्षमता विस्तारित मॉड्यूल में मौजूद है सरल मॉड्यूल एक नाम देने के लिए कोई जरूरत नहीं है, और सरल मॉड्यूल में कार्य करता है प्रकार के आधार पर camlp4 द्वारा उत्पन्न कर रहे । इन functors का मुहावरेदार इस्तेमाल होता है:

module Int = Complex(struct 
    type t = int 
end) 

समस्या प्रकट होता है जब मैं रिकॉर्ड के साथ काम कर रहा हूँ:

module Point2D = Complex(struct 
    type t = { x : int ; y : int } 
end) 

let (Some location) = Point2D.read db "location" 

वहाँ से ऊपर परिभाषित x और y क्षेत्रों तक पहुँचने का कोई आसान तरीका प्रतीत हो रहा है Point2D मॉड्यूल के बाहर, जैसे location.x या location.Point2D.x। इसे कैसे प्राप्त किया जा सकता है?

संपादित: के रूप में अनुरोध किया है, यहाँ एक पूरा कम से कम उदाहरण है कि इस मुद्दे को प्रदर्शित करता है है:

सभी की
module type TYPE = sig 
    type t 
    val default : t 
end 

module Make = functor(Arg : TYPE) -> struct 
    include Arg 
    let get = function None -> default | Some x -> (x : t) 
end 

module Made = Make(struct 
    type t = {a : int} 
    let default = { a = 0 } (* <-- Generated by camlp4 based on type t above *) 
end) 

let _ = (Made.get None).a (* <-- ERROR *) 
+1

कंपिल करने योग्य कोड पोस्ट करने से संकलित उत्तर प्राप्त करने में बहुत मदद मिलेगी। –

उत्तर

3

पहले, अपने पिछले कोड नमूने में, अंतिम पंक्ति, तो आप शायद .a बजाय .x मतलब है।

अपने कोड के साथ समस्या यह है कि, जिस तरह से साथ आप अपने Make functor को परिभाषित है, प्रकार tMade में सार है: वास्तव में, functors TYPE हस्ताक्षर जो {a : int} को सील कर एक सार प्रकार के रूप में इस्तेमाल करते हैं।

निम्नलिखित डिज़ाइन इस मुद्दे को बाधित करता है, लेकिन, यह एक अलग डिज़ाइन है।

module type TYPE = sig 
    type t 
    val default : t 
end 

module Extend = functor(Arg : TYPE) -> struct 
    open Arg 
    let get = function None -> default | Some x -> (x : t) 
end 

module T = struct 
    type t = {a : int} 
    let default = { a = 0 } 
end 

module Made = struct 
    include T 
    include Extend(T) 
end 

let _ = Made.((get None).a) 
1

समस्या यह है कि OCaml प्रकार t के योग्य घटकों का उल्लेख करने के लिए एक नाम नहीं है (इस मामले में एक रिकॉर्ड है, लेकिन एक ही समस्या सामान्य वेरिएंट के साथ मौजूद होगा) Made के बाहर है।

module F = struct 
    type t = {a : int} 
    let default = { a = 0 } 
end 

module Made = Make(F) 

let _ = (Made.get None).F.a (* <-- WORKS *) 

तुम भी स्पष्ट रूप से functorial आवेदन बाहर प्रकार घोषणा कर सकते हैं:

type rcd = {a : int} 

module Made = Make(struct 
    type t = rcd 
    let default = { a = 0 } 
end) 

let _ = (Made.get None).a (* <-- WORKS *) 
+0

आपके उत्तर के लिए धन्यवाद। मैं आपके पहले समाधान का उपयोग कर सकता हूं, लेकिन मैं केवल फ़ील्ड तक पहुंचने के लिए मॉड्यूल 'एफ' रखने के बजाय कुछ और अधिक सुरुचिपूर्ण दिख रहा हूं (क्योंकि उस मॉड्यूल का उपयोग किसी और चीज़ के लिए कभी नहीं किया जाएगा)। दूसरा समाधान काम नहीं करेगा, क्योंकि 'डिफ़ॉल्ट दें' उत्पन्न होता है और टाइप परिभाषा के ठीक बाद दिखाई देगा, इसलिए मुझे इसे मॉड्यूल में मैन्युअल रूप से कॉपी करना होगा (व्यावहारिक रूप से, यह वास्तव में कई मान हैं, केवल एक नहीं, इसलिए उन्हें कॉपी करना काफी वर्बोज़ है)। –

4

के शामिल मॉड्यूल में से कुछ के हस्ताक्षर पर नजर डालते हैं अनाम नामकरण समस्या का हल। ये ओकैम द्वारा उत्पन्न हस्ताक्षर हैं, और वे मुख्य हस्ताक्षर हैं, यानी वे सिद्धांत द्वारा अनुमत सबसे सामान्य हस्ताक्षर हैं।

module Make : functor (Arg : TYPE) -> sig 
    type t = Arg.t 
    val default : t 
    val get : t option -> t 
end 
module Made : sig 
    type t 
    val default : t 
    val get : t option -> t 
end 

सूचना कैसे समीकरण Make(A).t = A.t बनाए रखा है (ताकि Make(A).t एक पारदर्शी प्रकार संक्षिप्त नाम है), अभी तक Made.t सार है। ऐसा इसलिए है क्योंकि Made फ़ंक्शन को अज्ञात संरचना में लागू करने का परिणाम है, इसलिए इस मामले में तर्क प्रकार के लिए कोई कैनोलिक नाम नहीं है।

रिकॉर्ड प्रकार जनरेटिव हैं।अंतर्निहित प्रकार सिद्धांत के स्तर पर, सभी जनरेटिव प्रकार कन्स्ट्रक्टर और विनाशकों के लिए कुछ वाक्य रचनात्मक चीनी के साथ अमूर्त प्रकारों की तरह व्यवहार करते हैं। जनरेटिव प्रकार को नामित करने का एकमात्र तरीका इसका नाम देना है, या तो मूल नाम या जो कि मूल समीकरणों की एक श्रृंखला के माध्यम से मूल नाम तक फैला है।

पर विचार करें यदि आप Made की परिभाषा नकल क्या होता है:

module Made1 = Make(struct 
    type t = {a : int} 
    let default = { a = 0 } (* <-- Generated by camlp4 based on type t above *) 
    end) 
module Made2 = Make(struct 
    type t = {a : int} 
    let default = { a = 0 } (* <-- Generated by camlp4 based on type t above *) 
    end) 

आप दो अलग अलग प्रकार Made1.t और Made2.t मिलता है, भले ही परिभाषाओं के दाएँ हाथ के पक्ष एक ही हैं। यही जनरेटिविटी सब कुछ है।

चूंकि Made.t सार है, यह एक रिकॉर्ड प्रकार नहीं है। इसमें कोई कन्स्ट्रक्टर नहीं है। किसी नाम की कमी के लिए संरचना तर्क बंद होने पर रचनाकार खो गए थे।

ऐसा होता है कि रिकॉर्ड के साथ, अक्सर सिंटैक्टिक चीनी चाहता है लेकिन जनरेटिविटी नहीं। लेकिन ओकंपल में कोई संरचनात्मक रिकॉर्ड प्रकार नहीं है। इसमें जनरेटिव रिकॉर्ड प्रकार हैं, और इसमें ऑब्जेक्ट्स हैं, जो कि एक प्रकार के सैद्धांतिक दृश्य से सबस्क्यूम रिकॉर्ड हैं लेकिन अभ्यास में थोड़ा और काम करने के लिए थोड़ा सा काम हो सकता है और एक छोटा प्रदर्शन जुर्माना हो सकता है।

module Made_object = Make(struct 
    type t = <a : int> 
    let default = object method a = 0 end 
    end) 

या, आप एक ही प्रकार परिभाषा रखना चाहते हैं, तो आप प्रकार और उसके निर्माताओं, जो संरचना नामकरण का मतलब के लिए एक नाम देना होगा।

module A = struct 
    type t = {a : int} 
    let default = { a = 0 } (* <-- Generated by camlp4 based on type t above *) 
    end 
module MadeA = Make(A) 

ध्यान दें कि अगर आप Make(A) दो बार निर्माण, आप एक ही प्रकार के चारों ओर मिलता है।

module MadeA1 = Make(A) 
module MadeA2 = Make(A) 

(ठीक है, यह नहीं उल्लेखनीय यहाँ है, लेकिन आप अभी भी MadeA1 और MakeA2 में एक ही सार प्रकार प्राप्त होता ऊपर Made1 और Made2 मामले के विपरीत है। यही कारण है कि अब इन के लिए कोई नाम नहीं है क्योंकि है प्रकार: MadeA1.t = Make(A).t।)

+0

ग्रेट स्पष्टीकरण। अवधारणाओं पर एक नाम डालने ("जनरेटिव") ने काफी मदद की, भले ही यह मूल मुद्दे के लिए एक वास्तविक सुरुचिपूर्ण समाधान नहीं लाया। –