2010-12-02 10 views
19

समय-समय पर मैं उस समस्या से ठोकर खा रहा हूं जिसे मैं व्यक्त करना चाहता हूं "कृपया अंतिम तर्क दो बार उपयोग करें", उदा। पॉइंटफ्री शैली लिखने या लैम्ब्डा से बचने के लिए। जैसेहास्केल में "पुन: उपयोग" तर्क के लिए चाल?

sqr x = x * x 

रूप

sqr = doubleArgs (*) where 
    doubleArgs f x = f x x 

लिखा जा सकता है या यह थोड़ा और अधिक जटिल समारोह (this question से लिया गया) पर विचार करें:

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs) 

मैं इस कोड pointfree लिख सकता है अगर वहाँ की तरह एक समारोह थे यह:

ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where 
    dup f f1 f2 x = f (f1 x) (f2 x) 

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

उत्तर

26

Control.Monad से:

join :: (Monad m) -> m (m a) -> m a 
join m = m >>= id 

instance Monad ((->) r) where 
    return = const 
    m >>= f = \x -> f (m x) x 

विस्तार करना:

join :: (a -> a -> b) -> (a -> b) 
join f = f >>= id 
     = \x -> id (f x) x 
     = \x -> f x x 

तो, हाँ, Control.Monad.join

ओह, और अपने pointfree उदाहरण के लिए, आप अनुप्रयोगी अंकन का उपयोग (Control.Applicative से) की कोशिश की है:

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails 

(मैं भी नहीं जानता कि क्यों लोग a ++ (x:b) बजाय a ++ [x] ++ b का इतना ही शौक है ... यह तेज़ नहीं है - इनलाइनर इसका ख्याल रखेगा - और बाद वाला इतना अधिक सममित है! ओह ठीक है)

+2

और 'पॉइंटफ्री' के अनुसार, 'dup'' liftM2' होने के लिए काम करता है।मुझे वास्तव में कार्यों के लिए मोनैड इंस्टेंस पर बेहतर संभाल करने की आवश्यकता है। –

+2

ऐसी समस्याओं को हल करने के लिए ** ** ** ** देने के लिए दोनों का धन्यवाद। बीटीडब्ल्यू मैंने 'sqr = (*) <$> आईडी <*> आईडी' की कोशिश की और यह भी काम करता है :-) – Landei

+0

' ए ++ (x: b) 'आपके विकल्प से 3 वर्ण कम है, शायद यही कारण है कि कुछ लोग इसे पसंद करते हैं? –

11

जिसे आप 'डबलअर्ग' कहते हैं उसे अक्सर डुप्लिकेट कहा जाता है - यह डब्ल्यू कम्बाइनेटर (जिसे वारबलर कहा जाता है) टू मॉकिंग मॉकिंगबर्ड) - "प्राथमिक डुप्लीकेटर"।

जिसे आप 'डुप्ल' कहते हैं वह वास्तव में 'स्टार्लिंग-प्राइम' संयोजक है।

हास्केल के पास काफी छोटा "संयोजक आधार" डेटा है। फ़ंक्शन, प्लस कुछ आवेदक और मोनाडिक ऑपरेशंस आवेदक और मोनाड (< *> के लिए फ़ंक्शन उदाहरणों के आधार पर अधिक "मानक" संयोजक जोड़ते हैं, एस - कार्यात्मक उदाहरण के लिए स्टार्लिंग संयोजक, लिफ्टए 2 & लिफ्टएम 2 स्टारलिंग-प्राइम हैं)। डेटा का विस्तार करने के लिए समुदाय में बहुत उत्साह प्रतीत नहीं होता है। फ़ंक्शन, इसलिए जब संयोजक अच्छे मज़ेदार होते हैं, व्यावहारिक रूप से मैं उन परिस्थितियों में लंबे समय तक पसंद करता हूं जहां एक संयोजक सीधे उपलब्ध नहीं होता है।

+2

ओह, मुझे हास्केल के लिए "पक्षी-ऑपरेटर" मिले: http://hackage.haskell.org/packages/archive/data-aviary/0.2.3/doc/html/Data-Aviary-Birds.html – Landei

+2

@Landei - मैं उन्हें "संदर्भ केवल" मानता हूं, यानी मैं उनके कामकाजी कोड में उनके आधार पर अनुशंसा नहीं करता। मुझे कैबल विवरण को और अधिक स्पष्ट करना चाहिए कि वे "केवल संदर्भ" हैं, लेकिन मुझे अभी तक इसके चारों ओर नहीं मिला है। –

+2

क्या @ लांडेई कॉल 'डुप्ली' को जे में एक "क्रिया कांटा" के रूप में भी जाना जाता है (http://www.jsoftware.com/help/jforc/forks_hooks_and_compound_adv.htm), जहां यह ऑपरेटरों के सरल जुड़ाव द्वारा लिखा गया है, जैसे '(एफ जी एच) x'' dup f g h x' के बजाय x'। –

7

यहां मेरे प्रश्न के दूसरे भाग के लिए एक और समाधान है: तीर!

import Control.Arrow 

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++)) 

&&& ("फैनआउट") दो कार्यों के लिए एक तर्क वितरित करता है और परिणाम की जोड़ी देता है। >>> ("और फिर") फ़ंक्शन एप्लिकेशन ऑर्डर को उलट देता है, जो बाएं से दाएं संचालन की श्रृंखला की अनुमति देता है। second केवल एक जोड़ी के दूसरे भाग पर काम करता है। निश्चित रूप से आपको दो तर्कों की अपेक्षा करने वाले फ़ंक्शन में जोड़ी को खिलाने के अंत में uncurry की आवश्यकता है।

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