2015-05-18 13 views
8

में ग्लोबल पॉलिमॉर्फिक (वर्ग) मानों का पुन: उपयोग/ज्ञापन, यदि मैं पॉलिमॉर्फिक "ग्लोबल" वर्ग मान साझा करता/याद करता हूं, विशेष रूप से मॉड्यूल सीमाओं में साझा किया जाता है। मैंने this और this पढ़ा है, लेकिन वे मेरी स्थिति को प्रतिबिंबित नहीं करते हैं, और मैं जवाब से क्या उम्मीद कर सकता हूं उससे कुछ अलग व्यवहार देख रहा हूं।हास्केल

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} 

module A 

import Debug.Trace 

class Costly a where 
    costly :: a 

instance Num i => Costly i where 
    -- an expensive (but non-recursive) computation 
    costly = trace "costly!" $ (repeat 1) !! 10000000 

foo :: Int 
foo = costly + 1 

costlyInt :: Int 
costlyInt = costly 

और एक अलग मॉड्यूल:

module B 
import A 

bar :: Int 
bar = costly + 2 

main = do 
    print foo 
    print bar 
    print costlyInt 
    print costlyInt 

maincostly की दो अलग-अलग मूल्यांकन पैदावार (के रूप में द्वारा संकेत चल रहा है

एक वर्ग है कि एक मूल्य है कि गणना करने के लिए महंगा हो सकता है को उजागर करता है पर विचार करें ट्रेस): foo के लिए एक, और bar के लिए एक। मुझे पता है कि costlyInt सिर्फ रिटर्न foo से (का मूल्यांकन) costly, क्योंकि अगर मैं main से print foo को दूर तो पहले costlyInt महंगा हो जाता है। (। मैं भी, कोई बात नहीं क्या एक अलग मूल्यांकन प्रदर्शन करने के लिए Num a => a को foo के प्रकार के सामान्यीकरण से costlyInt पैदा कर सकता है)

मुझे लगता है कि मैं जानता हूँ कि क्यों इस व्यवहार होता है: Costly के कहने प्रभावी रूप से एक समारोह है कि एक Num लेता है शब्दकोश और Costly शब्दकोश उत्पन्न करता है। तो bar संकलित करते समय और costly के संदर्भ को हल करते समय, ghc एक ताजा Costly शब्दकोश उत्पन्न करता है, जिसमें इसका एक महंगा हिस्सा होता है। प्रश्न 1: क्या मैं इसके बारे में सही हूं?

costly का सिर्फ एक मूल्यांकन पैदा करने के लिए कुछ तरीके, जिनमें निम्न शामिल हैं:

    एक मॉड्यूल में
  • रखो सब कुछ।
  • Num i इंस्टेंस बाधा को हटाएं और केवल Costly Int उदाहरण को परिभाषित करें।

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

  • उदाहरण में costly परिभाषा पर इनलाइन, INLINABLE, या NOINLINE का उपयोग करना:

    भी बदल जाता है कि जैसे मूल्यांकन, की संख्या को कम नहीं करते हैं। (मुझे यह काम करने की उम्मीद नहीं थी, लेकिन हे, एक शॉट के लायक।)

  • उदाहरण परिभाषा में SPECIALIZE instance Costly Int प्रज्ञा का उपयोग करना।

बाद मेरे लिए आश्चर्य की बात है - मैं यह उम्मीद थी कि इसके बाद के संस्करण काम किया है दूसरे मद के लिए अनिवार्य रूप से बराबर हो। यही है, मैंने सोचा कि यह एक विशेष Costly Int शब्दकोश उत्पन्न करेगा, जो foo, bar, और costlyInt साझा करेगा। मेरा प्रश्न 2: मैं यहाँ क्या याद कर रहा हूँ?

मेरा अंतिम प्रश्न: क्या मैं चाहता हूं कि प्राप्त करने के लिए कोई अपेक्षाकृत सरल और मूर्ख तरीका है, यानी, किसी विशेष कंक्रीट प्रकार के costly के सभी संदर्भ मॉड्यूल में साझा किए जा रहे हैं? जो मैंने अभी तक देखा है, उससे मुझे संदेह है कि जवाब नहीं है, लेकिन मैं अभी भी उम्मीद कर रहा हूं।

+0

इस सवाल से अलग [मेरे पहले एक] (http://stackoverflow.com/questions/25057803/is-there-an-automatic-way-to-memoise-global-polymorphic-values-in- वास्तव में किस प्रकार है हास्केल)? – leftaroundabout

+0

मैं जो कह सकता हूं उससे, आपके प्रश्न में लागत शब्दकोष के साथ संयुक्त रिकर्सन से आता है, जो घातीय पुनर्मूल्यांकन का कारण बनता है। एक बार उत्तरार्द्ध तय हो जाने के बाद, गणना स्वयं तेज है। लेकिन यदि दो मॉड्यूल fibsImplicitDict को संदर्भित करते हैं, तो उन्हें अलग-अलग थंक्स मिलेंगे जिन्हें अलग से मूल्यांकन किया जाएगा। मैं इसे बर्दाश्त नहीं कर सकता, क्योंकि मेरी गणना मूल रूप से महंगा है (रिकर्सन के कारण नहीं)। –

+0

पीएस - तथ्य यह है कि उन पर बाधाओं के साथ कक्षा के उदाहरण भी एक भूमिका निभा रहे हैं, ऐसा लगता है। –

उत्तर

6

जीएचसी में साझाकरण नियंत्रण मुश्किल है। ऐसे कई अनुकूलन हैं जो जीएचसी करता है जो साझाकरण को प्रभावित कर सकता है (जैसे इनलाइनिंग, फ़्लोटिंग चीजें इत्यादि)।

Rec { 
bar_xs 
bar_xs = : x1_r3lO bar_xs 
end Rec } 

bar1 = $w!! bar_xs 10000000 
--  ^^^ this repeats the computation. bar_xs is just repeat 1 

bar = 
    case trace $fCostlyi2 bar1 of _ { I# x_aDm -> I# (+# x_aDm 2) } 
    --   ^^^ this is just the "costly!" string 

कि नहीं था ':

इस मामले में, सवाल क्यों विशेषज्ञ pragma इच्छित प्रभाव को प्राप्त नहीं किया था जवाब देने के लिए, के bar समारोह के विशेष रूप से, बी मॉड्यूल के कोर को देखो जैसा हम चाहते थे काम नहीं करते। costly का पुन: उपयोग करने के बजाय, जीएचसी ने costly फ़ंक्शन को केवल इनलाइन करने का निर्णय लिया।

इसलिए हमें जीएचसी को महंगा रूप से इनलाइन करने से रोकना है, या गणना डुप्लिकेट की जाएगी। हम यह कैसे करे? आप एक {-# NOINLINE costly #-} pragma जोड़ने पर्याप्त होगा सोच सकते हैं, लेकिन दुर्भाग्य से इनलाइन किए जाने वाले बिना विशेषज्ञता एक साथ अच्छी तरह से काम करने के लिए नहीं है:

A.hs:13:3: Warning: 
    Ignoring useless SPECIALISE pragma for NOINLINE function: ‘$ccostly’ 

लेकिन वहाँ GHC को समझाने के लिए हम क्या चाहते करने के लिए एक चाल है: हम costly लिख सकते हैं निम्नलिखित तरीके से:

instance Num i => Costly i where 
    -- an expensive (but non-recursive) computation 
    costly = memo where 
    memo :: i 
    memo = trace "costly!" $ (repeat 1) !! 10000000 
    {-# NOINLINE memo #-} 
    {-# SPECIALIZE instance Costly Int #-} 
-- (this might require -XScopedTypeVariables) 

यह हमें costly विशेषज्ञ, simultanously हमारे अभिकलन को इनलाइन करने से परहेज करेंगे अनुमति देता है।

+0

बकाया! मैंने मेमो चाल, और विशेष के साथ नोइनलाइन की कोशिश की थी (केवल एक ही त्रुटि प्राप्त करने के लिए), लेकिन इस तरह से उन्हें गठबंधन करने का विचार नहीं किया था। यह चाल मेरे कुछ वैश्विक मूल्यों के लिए काम करेगी, लेकिन दूसरों के लिए मैं विशेष नहीं कर सकता क्योंकि मुझे केवल शीर्ष अनुप्रयोग मॉड्यूल पर ठोस प्रकार पता है। क्या उस मामले के लिए कोई उम्मीद है? –

+0

@ChrisPeikert मैंने चेक नहीं किया है, लेकिन हो सकता है कि 'महंगा' इनलाइनिंग इस मामले में विशेषज्ञता के समान प्रभाव प्राप्त कर सके? – bennofs

+0

आह नहीं, इनलाइनिंग काम नहीं करती है: | – bennofs