एक पुस्तकालय implementor के दृष्टिकोण से, जिस तरह से इस डिबग करने के लिए संदिग्ध ऑपरेशन के लिए एक आवरण बनाने के लिए है, तो देखने के लिए कि संलयन काम किया है कोर कोड को देखो है।
-- Main.hs ---------------------------------------------------
import Solver
import Data.Array.Repa.IO.BMP
main
= do Right img <- readImageFromBMP "whatever.bmp"
print $ cumsumBMP img
-- Solver.hs --------------------------------------------------
{-# LANGUAGE TypeOperators, FlexibleContexts, TypeFamilies #-}
module Solver (cumsumBMP) where
import Data.Array.Repa as Repa
import Data.Word
{- all your defs -}
{-# NOINLINE cumsumBMP #-}
cumsumBMP :: Array DIM3 Word8 -> Array DIM3 Word8
cumsumBMP img = cumsum $ transpose img
मैं एक अलग मॉड्यूल में "solver" कोड डाल दिया है, इसलिए हम केवल परिभाषाओं हम के बारे में परवाह के लिए कोर कोड की खोजबीन करना है।
संकलित की तरह:
touch Solver.hs ; ghc -O2 --make Main.hs \
-ddump-simpl -dsuppress-module-prefixes -dsuppress-coercions > dump
letrec
कीवर्ड के लिए खोज cumsumBMP
की परिभाषा में जाओ और। letrec
के लिए खोज आंतरिक लूप को खोजने का एक त्वरित तरीका है।
नहीं बहुत दूर नीचे मैं इस देखें: (थोड़ा पुन: स्वरूपित)
case gen_a1tr
of _ {
GenManifest vec_a1tv ->
case sh2_a1tc `cast` ... of _ { :. sh3_a1iu sh4_a1iv ->
case ix'_a1t9 `cast` ... of _ { :. sh1'_a1iz sh2'_a1iA ->
case sh3_a1iu `cast` ... of _ { :. sh5_X1n0 sh6_X1n2 ->
case sh1'_a1iz `cast` ... of _ { :. sh1'1_X1n9 sh2'1_X1nb ->
case sh5_X1n0 of _ { :. sh7_X1n8 sh8_X1na ->
...
case sh2'1_X1nb of _ { I# y3_X1nO ->
case sh4_a1iv of _ { I# y4_X1nP ->
case sh2'_a1iA of _ { I# y5_X1nX ->
...
let { x3_a1x6 :: Int# [LclId]
x3_a1x6 =
+#
(*#
(+#
(*#
y1_a1iM
y2_X1nG)
y3_X1nO)
y4_X1nP)
y5_X1nX } in
case >=#
x3_a1x6
0
of ...
आपदा! x3_a1x6
बाध्यकारी स्पष्ट रूप से कुछ उपयोगी काम (गुणा, जोड़ों और इसी तरह) कर रहा है लेकिन यह अनलॉकिंग संचालन की एक लंबी श्रृंखला में लपेटा गया है जिसे प्रत्येक लूप पुनरावृत्ति के लिए भी निष्पादित किया जाता है। इससे भी बदतर यह है कि यह प्रत्येक पुनरावृत्ति पर सरणी की लंबाई और चौड़ाई (आकार) को अनबॉक्सिंग कर रहा है, और यह जानकारी हमेशा एक जैसी होगी। जीएचसी वास्तव में लूप से इन केस एक्सप्रेशन को फ्लोट करना चाहिए, लेकिन यह अभी तक नहीं है। यह Issue #4081 on the GHC trac का एक उदाहरण है, जो उम्मीद है कि जल्द ही कुछ समय तय किया जाएगा।
आसपास के काम आने वाले सरणी में deepSeqArray
लागू करना है। यह शीर्ष स्तर (लूप के बाहर) पर अपने मूल्य की मांग रखता है जो जीएचसी को पता चलता है कि मामले के मैचों को और आगे बढ़ाना ठीक है। cumsumBMP
की तरह एक समारोह के लिए, हम भी उम्मीद भेजे सरणी पहले से ही प्रकट हो सकता है, तो हम इस के लिए एक स्पष्ट मामला मैच जोड़ सकते हैं:
{-# NOINLINE cumsumBMP #-}
cumsumBMP :: Array DIM3 Word8 -> Array DIM3 Word8
cumsumBMP [email protected](Array _ [Region RangeAll (GenManifest _)])
= img `deepSeqArray` cumsum $ transpose img
फिर से संकलन, भीतरी पाश अब ज्यादा बेहतर लग रहा है:
letrec {
$s$wfoldlM'_loop_s2mW [...]
:: Int# -> Word# -> Word# [...]
$s$wfoldlM'_loop_s2mW =
\ (sc_s2mA :: Int#) (sc1_s2mB :: Word#) ->
case <=# sc_s2mA a_s2ji of _ {
False -> sc1_s2mB;
True ->
$s$wfoldlM'_loop_s2mW
(+# sc_s2mA 1)
(narrow8Word#
(plusWord#
sc1_s2mB
(indexWord8Array#
rb3_a2gZ
(+#
rb1_a2gX
(+#
(*#
(+#
(*#
wild19_X1zO
ipv1_X1m5)
sc_s2mA)
ipv2_X1m0)
wild20_X1Ct)))))
}; } in
यह एक तंग, पूंछ रिकर्सिव लूप है जो केवल आदिम परिचालन का उपयोग करता है। बशर्ते आप -fllvm -optlo-O3
के साथ संकलित करें, ऐसा कोई कारण नहीं है जो समकक्ष सी प्रोग्राम के रूप में तेज़ी से नहीं चलेगा।
वहाँ एक मामूली हिचकी जब यह हालांकि चल रहा है:
desire:tmp benl$ ./Main
Main: Solver.hs:(50,1)-(51,45): Non-exhaustive patterns in function cumsumBMP
यह सिर्फ हमें याद दिलाता है कि हम cumsumBMP
कॉल करने से पहले सरणी के लिए मजबूर करने की जरूरत है।
-- Main.hs ---------------------------------------------------
...
import Data.Array.Repa as Repa
main
= do Right img <- readImageFromBMP "whatever.bmp"
print $ cumsumBMP $ Repa.force img
सारांश में:
- आप जोड़ने की जरूरत है कुछ
deepSeqArray
और अपने शीर्ष स्तर पर गूप मिलान कार्यों GHC में एक वर्तमान नाकामयाबी के आसपास काम करने के लिए पैटर्न। यह द्वारा cumsumBMP
फ़ंक्शन के अंतिम संस्करण द्वारा प्रदर्शित किया गया है। यदि आप जीएचसी मुख्यालय को जल्द ही ठीक करना चाहते हैं तो अपने आप को Issue #4081 on the GHC trac पर एक सीसी के रूप में जोड़ें। जब यह तय किया जाता है तो रेपा कार्यक्रम बहुत सुंदर होंगे।
- आपको प्रत्येक फ़ंक्शन में गोद जोड़ने की आवश्यकता नहीं है। इस उदाहरण में मुझे
indexSlice
और दोस्तों को स्पर्श करने की आवश्यकता नहीं थी। सामान्य नियम force
, fold
या sumAll
का उपयोग करने वाले कार्यों में जाने के लिए है। ये फ़ंक्शंस उन वास्तविक लूप को तुरंत चालू करते हैं जो सरणी डेटा पर काम करते हैं, यानी, वे एक देरी सरणी को एक मैनिफेस्ट मान में परिवर्तित करते हैं।
- रेपा कोड के एक टुकड़े का प्रदर्शन उस संदर्भ द्वारा उतना ही निर्धारित किया जाता है जिसमें इसे वास्तविक कोड के रूप में उपयोग किया जाता है। यदि आप अपने शीर्ष स्तर के कार्यों को देरी से गुजरते हैं तो वे बहुत धीमे चलेंगे। The Repa Tutorial में इसकी और चर्चा है।
- रेपा-आईओ लाइब्रेरी के साथ पढ़ने वाली बीएमपी फाइलें पूर्व-मजबूर नहीं हैं, इसलिए आपको उपयोग से पहले उन्हें मजबूर करने की आवश्यकता है। यह शायद गलत डिफ़ॉल्ट है, इसलिए मैं इसे अगले संस्करण में बदल दूंगा।
वाह, मैं आपको एक बियर साथी का भुगतान करता हूं। उत्तर के लिए धन्यवाद, यह बेहद उपयोगी था। यह पुस्तकालय (रेपा) बकाया है। मैं निश्चित रूप से अंक # 4081 पर सीसी में फेंक दूंगा। जिस सीवी लाइब्रेरी पर मैं काम कर रहा हूं वह गिटूब और अंततः हैकेज पर जा रहा है, इसलिए यह सभी के लिए एक लाभ होगा। – nightski