2011-05-23 3 views
17

का एक ब्लॉक है कि इस तरह दिखना स्वीकार करता है कैसे बनाएं:एक पर्ल सबरूटीन कि मैं सबरूटीन्स का एक सेट है कोड

sub foo_1($) { 
    my $name = shift; 
    my $f; 

    run_something(); 
    open($f, $name) or die ("Couldn't open $name"); 
    while (<$f>) { 
    //Something for foo_1() 
    } 
    close($f); 
    do_something_else(); 

} 

और मैं चार या उससे अधिक की तरह है कि एक ही लग रहे हैं, केवल एक चीज बदल जाता है कि जबकि ब्लॉक ब्लॉक का शरीर है। मैं इसे सारण करना चाहता हूं और कोड को कॉपी-पेस्ट करना बंद कर दूंगा।

  • क्या कोई सबराउटिन कोड करने का कोई तरीका है जो कोड के ब्लॉक को स्वीकार करता है और इसे निष्पादित करता है?

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

+0

सामान्य शब्दों में, समारोह प्रोटोटाइप आवश्यक नहीं हैं और मैं उन्हें थोड़े बेकार हो पाते हैं। – jiggy

+0

@jiggy क्या आप थोड़ा सा विस्तार कर सकते हैं, कृपया? –

+1

=> इस मामले में, '($)' प्रोटोटाइप का उपयोग करने का अर्थ यह नहीं हो सकता कि इसका क्या अर्थ है। इसका मतलब है "मुझे एक तर्क दें", लेकिन इसका अर्थ यह भी है कि "उस तर्क पर स्केलर संदर्भ लगाएं"। तो यदि आपके पास एक तत्व के साथ एक सरणी थी, और उसे 'foo_1 @ array' कहा जाता है, तो' foo_1' संख्या '1' पारित की जाएगी, जो सरणी में तत्वों की गणना है। वास्तव में पहला तर्क प्राप्त करने के लिए, आपको इसे 'foo_1 $ array [0] 'के रूप में कॉल करने की आवश्यकता होगी। यदि आपके पास प्रोटोटाइप नहीं है, तो आप इसे 'foo_1 @ array' के रूप में बुला सकते थे और यह ठीक से काम करता। –

उत्तर

34

पर्ल एक प्रणाली सबरूटीन प्रोटोटाइप है कि आप उपयोगकर्ता बाद के चरणों कि एक तरह से निर्मित कार्यों के समान में पार्स करने के लिखने की अनुमति प्रदान करता है कहा जाता है। जिन बिल्डरों को आप अनुकरण करना चाहते हैं वे map, grep, या sort हैं जो प्रत्येक ब्लॉक को उनके पहले तर्क के रूप में ले सकते हैं।

या एक शाब्दिक सबरूटीन \&mysub कि प्रोटोटाइप के साथ, आप sub name (&) {...} का उपयोग जहां & पर्ल बताता है कि कार्य करने के लिए पहला तर्क या तो एक ब्लॉक (के साथ या sub के बिना) है करने के लिए,। (&) प्रोटोटाइप एक और केवल एक तर्क निर्दिष्ट करता है, यदि आपको कोड ब्लॉक के बाद एकाधिक तर्क पारित करने की आवश्यकता है, तो आप इसे (&@) के रूप में लिख सकते हैं जिसका अर्थ है, एक कोड के बाद एक कोड ब्लॉक।

sub higher_order_fn (&@) { 
    my $code = \&{shift @_}; # ensure we have something like CODE 

    for (@_) { 
     $code->($_); 
    } 
} 

वह सबराउटिन उत्तीर्ण सूची के प्रत्येक तत्व पर पारित ब्लॉक को चलाएगा। \&{shift @_} थोड़ा सा गूढ़ दिखता है, लेकिन यह सूची के पहले तत्व को बंद कर देता है, जो एक कोड ब्लॉक होना चाहिए। &{...} मूल्य को सबराउटिन (किसी ओवरलोडिंग का आविष्कार) के रूप में मानता है, और फिर \ तुरंत इसका संदर्भ लेता है। यदि मूल्य एक कोड रेफरी था, तो यह अपरिवर्तित लौटा दिया जाता है। अगर यह एक अधिभारित वस्तु थी, तो यह कोड में बदल गया है। अगर इसे कोड में शामिल नहीं किया जा सका, तो एक त्रुटि फेंक दी जाती है।

इस सबरूटीन फोन के लिए, आप लिखते थे:

higher_order_fn {$_ * 2} 1, 2, 3; 
# or 
higher_order_fn(sub {$_ * 2}, 1, 2, 3); 

(&@) प्रोटोटाइप ही काम करता है की सुविधा देता है कि आप एक map/grep ब्लॉक की तरह के रूप में तर्क बारे में जब एक समारोह के रूप उच्च आदेश समारोह का उपयोग कर। यदि आप एक तरीके के रूप में प्रयोग कर रहे हैं, तो आप प्रोटोटाइप को छोड़ देते हैं और यह इस तरह से लिखना चाहिए:

sub higher_order_method { 
    my $self = shift; 
    my $code = \&{shift @_}; 
    ... 
    $code->() for @_; 
} 
... 
$obj->higher_order_method(sub {...}, 'some', 'more', 'args', 'here'); 
+1

उत्तर के लिए धन्यवाद, एरिक। –

+0

... जारी रखा (मैंने गलती से प्रवेश किया) मैं जानना चाहता हूं कि आप \ & {shift @_} का उपयोग क्यों करते हैं। लोगों ने मुझे दिए गए अन्य उत्तरों से अलग क्यों है? मैं पर्ल के लिए काफी नया हूं (लेकिन मैंने हास्केल, जावा, स्कीम और सी में कुछ समय कोड किया है)। धन्यवाद। –

+0

यह सत्यापित करने का एक छोटा सा तरीका है कि तर्क वास्तव में एक कोड संदर्भ है। विस्तारित इसका अर्थ है 'do {my $ x = shift; $ x eq 'कोड' ref? $ x: अधिभार :: अधिभारित ($ _ [0], 'और {}')? \ & $ x: "कोड संदर्भ नहीं" मरें "}। प्रोटोटाइप एक संकलित समय बाधा है जो आपके लिए कोड संदर्भ के लिए जांच करता है, लेकिन उप को 'और' सिगिल (या कोड को विधि के रूप में कॉल करके) को कॉल करके इसे बाईपास किया जा सकता है। '\ & {Shift @_}' उस बाईपास के विरुद्ध एक अतिरिक्त जांच है। –

11
sub bar { 
    my ($coderef) = @_; 
    ⁝ 
    $coderef->($f, @arguments); 
    ⁝ 
} 

bar(sub { my ($f) = @_; while … }, @other_arguments); 

या शायद थोड़ा कम एक नामित coderef के साथ उलझ:

my $while_sub = sub { 
    my ($f) = @_; 
    while … 
    ⁝ 
}; 
bar($while_sub, @other_arguments); 

संपादित: Higher-Order Perl पुस्तक प्रोग्रामिंग की इस तरह से भरा है।

+0

बहुत बहुत धन्यवाद। मुझे लगता है कि मैं उस पुस्तक को पढ़ूंगा। सुनने में अच्छा लग रहा हैं! –

9

आप & प्रोटोटाइप चाहते हैं।

sub foo(&@) { 
    my ($callback) = shift; 
    ... 
    $callback->(...); 
    ... 
} 

foo { ... } ...; 

बराबर बनाता

foo(sub { ... }, ...); 
संबंधित मुद्दे