2016-02-25 4 views
5

यह सवाल मैं here पूछा के एक भाग को आसान बनाने का एक प्रयास है:मैं जूलिया में खुले अंत प्रकार के साथ एक विशेषता कैसे लिख सकता हूं?

मैं कुछ कोड है कि प्रकार है कि कुछ मानदंडों को पूरा पर काम करने की गारंटी है लिखना चाहते हैं।

immutable Example 
    whatever::ASCIIString 
end 
function step_one(x::Example) 
    length(x.whatever) 
end 
function step_two(x::Int64) 
    (x * 2.5)::Float64 
end 
function combine_two_steps{X}(x::X) 
    middle = step_one(x) 
    result = step_two(middle) 
    result 
end 
x = Example("Hi!") 
combine_two_steps(x) 

चल रहा है इस काम करता है::

julia> x = Example("Hi!") 
Example("Hi!") 

julia> combine_two_steps(x) 
7.5 

फिर एक और दिन मैं कुछ और कोड लिखें:

immutable TotallyDifferentExample 
    whatever::Bool 
end 
function step_one(x::TotallyDifferentExample) 
    if x.whatever 
     "Hurray" 
    else 
     "Boo" 
    end 
end 
function step_two(x::ASCIIString) 
    (Int64(Char(x[end])) * 1.5)::Float64 
end 

और तुम क्या पता है, मेरी सामान्य है की आज कहते हैं कि मैं कुछ कोड लिखने दें गठबंधन समारोह अभी भी काम करता है!

julia> y = TotallyDifferentExample(false) 
TotallyDifferentExample(false) 

julia> combine_two_steps(y) 
166.5 

Hurray! लेकिन, कहें कि यह देर रात है और मैं इसे तीसरे उदाहरण पर फिर से करने की कोशिश कर रहा हूं। मुझे step_one लागू करना याद है, लेकिन मैं step_two को लागू करना भूल जाता हूं!

immutable ForgetfulExample 
    whatever::Float64 
end 
function step_one(x::ForgetfulExample) 
    x.whatever+1.0 
end 

अब जब मैं इसे चलाता हूं, तो मुझे रन-टाइम त्रुटि मिल जाएगी!

julia> z = ForgetfulExample(1.0) 
ForgetfulExample(1.0) 

julia> combine_two_steps(z) 
ERROR: MethodError: `step_two` has no method matching step_two(::Float64) 

अब, मैं एक प्रबंधक है, जो मुझे मार अगर मैं कभी भी एक रन-टाइम त्रुटि मिल जाएगा के लिए काम करते हैं। तो मुझे अपने जीवन को बचाने के लिए क्या करना है, वह एक ऐसा ट्राइट लिखना है जो अनिवार्य रूप से कहता है "अगर इस प्रकार का गुण लागू होता है, तो combine_two_steps पर कॉल करना सुरक्षित है।"

मैं तो मुझे पता था कि अगरcombine_two_steps कभी है भेजा तरह

using Traits 
@traitdef ImplementsBothSteps{X} begin 
    step_one(X) -> Y 
    step_two(Y) -> Float64 
end 
function combine_two_steps{X;ImplementsBothSteps{X}}(x::X) 
    middle = step_one(x) 
    result = step_two(middle) 
    result 
end 

b/c कुछ लिखना चाहते हैं, तो यह होगा एक त्रुटि को ऊपर उठाने के बिना रन है कि इन तरीकों डॉन अस्तित्व में नहीं है

समतुल्य रूप से, istrait(ImplementsBothSteps{X}) (सत्य होने के नाते) combine_two_steps के बराबर है बिना किसी त्रुटि-रहित-विधियों के त्रुटि के बिना चलाएगा।

लेकिन, जैसा कि सभी जानते हैं, मैं उस विशेषता परिभाषा का उपयोग नहीं कर सकता, क्योंकि Y का कोई मतलब नहीं है। (वास्तव में, अजीब तरह से पर्याप्त कोड, त्रुटि के बिना संकलित

julia> @traitdef ImplementsBothSteps{X} begin 
      step_one(X) -> Y 
      step_two(Y) -> Float64 
     end 

julia> immutable Example 
      whatever::ASCIIString 
     end 

julia> function step_one(x::Example) 
      length(x.whatever)::Int64 
     end 
step_one (generic function with 1 method) 

julia> function step_two(x::Int64) 
      (x * 2.5)::Float64 
     end 
step_two (generic function with 1 method) 

julia> istrait(ImplementsBothSteps{Example}) 
false 

लेकिन प्रकार के लक्षण भले ही तरीकों कुछ Y के लिए मौजूद हैं संतुष्ट नहीं है।) मेरी पहली सोचा मैं Any की तरह कुछ करने के लिए Y बदल सकते हैं

using Traits 
@traitdef ImplementsBothSteps{X} begin 
    step_one(X) -> Any 
    step_two(Any) -> Float64 
end 

लेकिन यह भी विफल रहता है b/c Any वास्तव में Some की तरह कुछ है, न कि सचमुच Any प्रकार (मैं कार्यान्वित एक विधि step_two कि इनपुट के रूप में किसी भी प्रकार का समय लग सकता है कभी नहीं के बाद से), लेकिन कुछ खास माना जाता हैटाइप करें जो दोनों लाइनों में साझा किया गया है!

तो सवाल यह है कि: आप इस स्थिति में क्या करेंगे?आप "spec" (यहां ट्राइट द्वारा व्यक्त किए गए अनुबंध के रूप में) के आसपास गुजरना चाहते हैं, इस तरह कि कोई भी प्रोग्रामर जो भी spec को पूरा करता है, आपके फ़ंक्शन combine_two_steps का उपयोग करने में सक्षम होने की गारंटी देता है, लेकिन spec अनिवार्य रूप से एक अस्तित्वत्मक क्वांटिफ़ायर है इसकी परिभाषा में।

क्या कोई कामकाज है? "Spec" लिखने के लिए एक बेहतर तरीका (उदाहरण के लिए "लक्षणों का उपयोग न करें, कुछ और उपयोग करें"?)

वैसे, यह उत्पन्न हो सकता है, लेकिन उपर्युक्त प्रश्न और यह प्रश्न आ रहा है एक परियोजना में नियमित रूप से ऊपर मैं काम कर रहा हूँ। मैं अनिवार्य रूप से इस समस्या के कारण एक रोडब्लॉक पर फंस गया हूं और बदसूरत कामकाज है जो मामला-दर-मामला काम करता है, लेकिन सामान्य मामले के लिए कोई दृष्टिकोण नहीं है।

उत्तर

1

Any का उपयोग करने के मेरे प्रश्न में सुझाव पर सामान्यीकरण वास्तव में भी काम कर सकता है, हालांकि यह बदसूरत है और वास्तव में इस बिंदु पर नहीं पहुंचता है। मान लीजिए आप पहले से ही लागू कर दिया है तरीकों

step_one(X) -> Y 
step_two(Y) -> Z 

तो फिर तुम के रूप में

@traitdef implements_both_steps begin 
    step_one(X) -> Any 
    step_two(Any) -> Z 
end 

विशेषता लिख ​​सकते हैं और बस एक डमी विधि

function step_two(x::Any) 
    typeof(x)==Y ? step_two(x::Y) : error("Invalid type") 
end 

यह रूप में अच्छी तरह एक मैक्रो में लिपटे जा सकती जोड़ने पैटर्न को दोहराने पर बचाने के लिए, और फिर एक बार उस विधि को लागू करने के बाद विशेषता संतुष्ट हो जाती है। यह एक हैक है जिसका मैं उपयोग कर रहा हूं (और वह काम करता है) बी/सी यह काफी सरल है, लेकिन समाधान मेरे प्रश्न की भावना में नहीं है।

+0

क्या आप विवरण पोस्ट कर सकते हैं। –

1

इस संतोषजनक है:

@traitdef ImplementsStep2{Y} begin 
    step_two(Y) -> Float64 
end 

# consider replacing `any` with `all` 
@traitdef AnotherImplementsBothSteps{X} begin 
    step_one(X) 
    @constraints begin 
     any([istrait(ImplementsStep2{Y}) for Y in Base.return_types(step_one,(X,))]) 
    end 
end 
इन विशेषता परिभाषाओं हम साथ

:

julia> istrait(ImplementsStep2{Int64}) 
true 

julia> istrait(AnotherImplementsBothSteps{Example}) 
true 

चाल का उपयोग करने के @constraints मूल रूप से गैर-सीधा सामान करना है। और विधि के लिए रिटर्न प्रकार प्राप्त करने के लिए Base.return_types का उपयोग करने के लिए। माना जाता है कि यह एक हैक का थोड़ा सा है, लेकिन यह मेरी खुदाई के साथ आया है। शायद Traits.jl का भविष्य संस्करण इसके लिए बेहतर उपकरण होगा।

मैंने विशेषता परिभाषा में any का उपयोग किया है। यह थोड़ा ढीला है। all का उपयोग करना कठोर हो सकता है लेकिन संकलन-समय की जांच के स्तर के आधार पर, बाधा का बेहतर प्रतिनिधित्व करता है।

बेशक, जूलिया का आत्मनिरीक्षण और try ... catch रन-टाइम पर यह सब जांच करने की अनुमति देता है।

+0

Base.return_types का उपयोग करने की रणनीति दिलचस्प है। आपने प्रभावी रूप से कोड लिखा है जो "अस्तित्वत्मक मात्रात्मक" चरण को प्रतिबिंबित करता है। मुझे यह पसंद है। मैं इसके बारे में थोड़ा और सोचने जा रहा हूं। इस पूरी चीज को "मेटा" मैक्रो में लपेटा जा सकता है, वास्तव में, प्रक्रिया को अंतिम उपयोगकर्ता को सरल बनाने के लिए। हालांकि मैं इस रणनीति के प्रदर्शन की जांच करना चाहता हूं। क्या आप अपने सिर के शीर्ष से जानते हैं यदि यह प्रदर्शन हिट करने के लिए लक्षणों पर विधि प्रेषण का कारण बनता है? – Philip

+0

यदि कंपाइलर संकलन करते समय पैरामीटर के प्रकारों का अनुमान लगा सकता है, तो प्रदर्शन प्रदर्शन नहीं होना चाहिए (प्रारंभिक पीढ़ी और शामिल कार्यों के संकलन को छोड़कर)। दूसरी तरफ, यदि प्रकार अज्ञात हैं, तो यह संभवतः सही फ़ंक्शन का अनुमान लगाने के लिए एक प्रदर्शन हिट हो सकता है, लेकिन जेनरेट किया गया फ़ंक्शन कैश किया जाता है, इसलिए उम्मीद है कि यह अभी भी एक बार किया जाएगा।जूलिया में यह सामान्य कहानी है, जब प्रकार स्थिर और अनुमानित होते हैं, शीर्ष प्रदर्शन प्राप्त होता है (बीटीडब्ल्यू 'मौर्यो 3' के लिए एक बड़ा अपवर्तनीय है, जिसने 'Traits.jl' लिखा था)। –

+0

'Traits.jl' द्वारा उपयोग की जाने वाली विधियों को गिटब रेपो के' README.md' में गहराई से समझाया गया है (लिंक: https://github.com/mauro3/Traits.jl) –

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