2011-04-06 15 views
6

मैं फ़ाइलों और डेटा के कुछ प्रसंस्करण करने के लिए एक ढांचा बनाने की कोशिश कर रहा हूं। जिस क्षेत्र में मैं संघर्ष कर रहा हूं वह यह है कि ढांचे में लॉगिंग फ़ंक्शन कैसे प्रदान किया जाए, जिससे फ्रेमवर्क उपयोग में लॉगिंग के ज्ञान के बिना संदेश की रिपोर्ट करने की अनुमति दे।मैं printf शैली लॉगिंग तर्क के साथ एक F # फ़ंक्शन कैसे बना सकता हूं?

let testLogger (source:seq<'a>) logger = 
    logger "Testing..." 
    let length = source |> Seq.length 
    logger "Got a length of %d" length 


let logger format = Printf.kprintf (printfn "%A: %s" System.DateTime.Now) format 
testLogger [1; 2; 3] logger 

आदर्श रूप में मैं इस कोड काम करना चाहता हूँ, लेकिन मैं बाहर काम नहीं कर सकता है कि कैसे में लकड़हारा समारोह पारित करने के लिए।

+0

आपको इसमें रुचि हो सकती है: http://stackoverflow.com/questions/5277902/printf-style-logging-for-f – Daniel

+0

मैंने इसे देखा है, लेकिन यह मेरी मदद नहीं करता है क्योंकि मैं नहीं करता हूं ' t फ्रेमवर्क को लॉग 4net –

+0

के बारे में जानना चाहते हैं, पहले जवाब देखें, इसका लॉग 4नेट से कोई लेना देना नहीं है। – Daniel

उत्तर

10

दुर्भाग्य से, आप अन्य कार्यों के लिए पैरामीटर के रूप में printf जैसे कार्यों पारित नहीं हो सकता और उसके बाद का उपयोग कई अलग-अलग तर्कों के साथ। समस्या यह है कि printfPrintf.TextWriterFormat<'a> -> 'a प्रकार का एक सामान्य कार्य है। प्रकार पैरामीटर 'a के लिए प्रतिस्थापित वास्तविक प्रकार कुछ फ़ंक्शन प्रकार है जो प्रत्येक बार printf (उदाहरण के लिए 'a == string -> unit"%s" आदि) का उपयोग करते हैं।

एफ # में, आपके पास एक फ़ंक्शन का पैरामीटर नहीं हो सकता है जो स्वयं एक सामान्य कार्य है। जेनेरिक फ़ंक्शन को कुछ वैश्विक फ़ंक्शन होना होगा, लेकिन आप इसे उस फ़ंक्शन द्वारा पैरामीटर कर सकते हैं जो वास्तव में स्ट्रिंग के साथ कुछ करता है। यह अनिवार्य रूप से क्या kprintf करता है, लेकिन आप अपने कार्य बेहतर नाम कर सकते हैं:

let logPrintf logger format = 
    Printf.kprintf logger format 

लकड़हारा द्वारा parameterized समारोह का एक उदाहरण होगा: टॉमस बताते हैं के रूप में

let testLogger (source:seq<'a>) logger = 
    logPrintf logger "Testing..." 
    let length = source |> Seq.length 
    logPrintf logger "Got a length of %d" length 


let logger = printfn "%A: %s" System.DateTime.Now 
testLogger [1; 2; 3] logger 
12

, एफ # में कार्य कर सकते हैं ' टी polymorphic तर्क की आवश्यकता नहीं है। इस मामले में, मुझे लगता है कि टॉमस का दृष्टिकोण काफी अच्छा है, क्योंकि आपको शायद string -> unit फ़ंक्शन को पास करने में सक्षम होना चाहिए जिसका उपयोग लॉगिंग के लिए किया जाता है।

type ILogger = abstract Log : Printf.StringFormat<'a,unit> -> 'a 

let testLogger (source:seq<'a>) (logger:ILogger) = 
    logger.Log "Testing..." 
    let length = source |> Seq.length   
    logger.Log "Got a length of %d" length 

let logger = { 
    new ILogger with member __.Log format = 
     Printf.kprintf (printfn "%A: %s" System.DateTime.Now) format } 

:

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

module Log = 
    let logWith (logger : ILogger) = logger.Log 

let testLogger2 (source:seq<'a>) logger = 
    Log.logWith logger "Testing..." 
    let length = source |> Seq.length   
    Log.logWith logger "Got a length of %d" length 

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

+0

+1 मुझे आपका पहला दृष्टिकोण पसंद है क्योंकि आप वैश्विक कार्यों से बच सकते हैं। –

+0

अच्छा दृष्टिकोण। मैंने टॉमस को सही उत्तर के रूप में चिह्नित किया है, लेकिन मुझे इस दृष्टिकोण को पसंद है, जिसका मैं शायद उपयोग करूंगा –

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