2012-04-22 13 views
8

में आंशिक गणना का अनुकूलन मैं उत्सुक कैसे इस कोड का अनुकूलन करने के हूँ:हास्केल

fun n = (sum l, f $ f0 l, g $ g0 l) 
    where l = map h [1..n] 

यह मानते हुए कि f, f0, g, g0, और h सभी महंगे होते हैं, लेकिन निर्माण और l के भंडारण अत्यंत है महंगा।

लिखित के रूप में, l तब तक संग्रहीत किया जाता है जब तक लौटा हुआ ट्यूपल पूरी तरह से मूल्यांकन नहीं किया जाता है या कचरा एकत्र नहीं किया जाता है। इसके बजाए, length l, f0 l, और g0 l सभी को निष्पादित किया जाना चाहिए जब भी उनमें से कोई भी निष्पादित हो, लेकिन f और g में देरी होनी चाहिए।

यह इस व्यवहार लेखन द्वारा निर्धारित किया जा सकता है प्रकट होता है:

fun n = a `seq` b `seq` c `seq` (a, f b, g c) 
    where 
    l = map h [1..n] 
    a = sum l 
    b = inline f0 $ l 
    c = inline g0 $ l 

या बहुत समान:

fun n = (a,b,c) `deepSeq` (a, f b, g c) 
    where ... 

हम शायद रूप में अच्छी तरह से एक ही प्रभाव को प्राप्त करने के लिए आंतरिक प्रकार का एक समूह निर्दिष्ट कर सकते हैं, जो दर्दनाक लग रहा है। क्या कोई अन्य विकल्प भी हैं?

इसके अलावा, मैं स्पष्ट रूप से मेरे inline कि संकलक sum, f0, और g0 फ़्यूज़ एकल लूप कि निर्माण करती है और अवधि द्वारा l अवधि की खपत में साथ उम्मीद कर रहा हूँ। मैं मैन्युअल इनलाइनिंग के माध्यम से यह स्पष्ट कर सकता हूं, लेकिन वह चूसना होगा। क्या कभी भी बनाए जाने और/या इनलाइनिंग को मजबूर करने से सूची l सूची को स्पष्ट रूप से रोकने के तरीके हैं? अगर संकलन के दौरान इनलाइनिंग या संलयन विफल हो तो चेतावनियां या त्रुटियां उत्पन्न होती हैं?

एक अलग रूप में के रूप में, मैं क्यों seq, inline, lazy, आदि सभी प्रस्तावना में let x = x in x द्वारा करने के लिए परिभाषित कर रहे हैं के बारे में उत्सुक हूँ। क्या यह बस उन्हें कंपाइलर को ओवरराइड करने की परिभाषा देने के लिए है?

+4

अंतिम प्रश्न के जवाब में: http://stackoverflow.com/a/8654407/1011995 –

+0

'f0' और 'g0' पूरी तरह से मनमानी हैं, या वे' फ़ोल्डर 'के संदर्भ में लिखे जा सकते हैं? – dave4420

+1

एक (ए, बी, सी) -एक्यूमुलेटर के साथ एक साधारण गुना नहीं होगा? – Sarah

उत्तर

3

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

आप

fun n = a `seq` b `seq` c `seq` (a, f b, g c) 
    where 
    l = map h [1..n] 
    a = sum l 
    b = inline f0 $ l 
    c = inline g0 $ l 

लिख सकते हैं या deepseq संस्करण तत्संबंधी, संकलक एक एकल के दौरान समानांतर (संगामिति अर्थ में नहीं) में किया जा करने के लिए a, b और c की संगणना विलय करने के लिए सक्षम हो सकता है, तो l का ट्रैवर्सल, लेकिन समय के लिए, मुझे विश्वास है कि जीएचसी नहीं करता है, और अगर मुझे जेएचसी या यूएचसी ने किया तो मुझे आश्चर्य होगा। और उसके लिए b और c कंप्यूटिंग की संरचना काफी सरल होने की आवश्यकता है।

संकलक और कंपाइलर संस्करणों में वांछित परिणाम प्राप्त करने का एकमात्र तरीका यह स्वयं करना है। कम से कम अगले कुछ वर्षों के लिए।f0 और g0 पर

आधार पर, यह प्रसिद्ध औसत

data P = P {-# UNPACK #-} !Int {-# UNPACK #-} !Double 

average :: [Double] -> Double 
average = ratio . foldl' count (P 0 0) 
    where 
    ratio (P n s) = s/fromIntegral n 
    count (P n s) x = P (n+1) (s+x) 

तरह उचित संचायक प्रकार के साथ एक सख्त बाईं गुना कर रहे हैं और समारोह के संयोजन, के रूप में लेकिन अगर f0 और/या g0 की संरचना के रूप में सरल हो सकता है फिट नहीं है, कहें कि एक बाएं गुना है और दूसरा सही गुना है, एक ट्रैवर्सल में गणना करना असंभव हो सकता है। ऐसे मामलों में, विकल्प l को पुनर्निर्मित करने और l को संग्रहीत करने के बीच है। l को संग्रहीत करना स्पष्ट साझाकरण (where l = map h [1..n]) के साथ प्राप्त करना आसान है, लेकिन यह पुन: प्रयास करना मुश्किल हो सकता है यदि संकलक कुछ सामान्य उप-अभिव्यक्ति उन्मूलन करता है (दुर्भाग्यवश, जीएचसी के पास उस रूप की सूचियों को साझा करने की प्रवृत्ति है, भले ही यह थोड़ा सीएसई करे)। जीएचसी के लिए, झंडे fno-cse और -fno-full-laziness अवांछित साझाकरण से बचने में मदद कर सकते हैं।

+0

आह, बाएं बनाम सही गुना के बारे में दिलचस्प बिंदु! हालांकि मैं आपके सीएसई बिंदु के बारे में थोड़ा उलझन में हूं। क्या आप बस यह देख रहे हैं कि सीएसई इस समस्या को बना सकता है जब आप इसे चारों ओर कोड करने की कोशिश करते हैं? –

+0

यदि स्टोर को स्टोर करने के बजाय सूची को फिर से बनाना सस्ता है, तो आप उदास लिखेंगे। 'एफ 0 (मानचित्र एच [1 .. एन])' और 'जी 0 (मानचित्र एच [1 .. एन])'। लेकिन संकलक सामान्य उप-अभिव्यक्ति 'मानचित्र एच [1 .. एन]' को खत्म कर सकता है और इसे गणना के बीच साझा कर सकता है। इसे रोकना, अगर यह अवांछित है, तो विपरीत के रूप में सीधा नहीं है, एक उप-अभिव्यक्ति साझा करना (जो किया जाता है यदि आप इसे किसी नाम से बांधते हैं, 'जहां l = map h [1 .. n] ')। असल में, हां, सीएसई उस समस्या को पेश कर सकता है, और आसपास काम करना मुश्किल हो सकता है। –