माउस मूव इवेंट के लिए मेरे इवेंट हैंडलर को डिबग करना, मैंने यह कोड लिखा है:

 unless (scrollDelta == Tuple 0 0) $ trace (show scrollDelta) \_ -> do ...

और मुझे कंसोल आउटपुट मिलता है

Tuple 0 0

इसके पीछे का विचार माउस की स्थिति में अंतर को सहेजना है जब भी उपयोगकर्ता माउस को पहले माउस बटन दबाकर ले जाता है।

क्या यह एक कंपाइलर बग है?

मेरा समाधान scrollDelta के प्रकार को Maybe (Tuple Int Int) में बदलना है जहां Nothing Tuple 0 0 के बजाय "बटन दबाए जाने पर कोई माउस आंदोलन नहीं" का प्रतिनिधित्व करता है, जो काम करता है।

1
ruben.moor 27 नवम्बर 2020, 20:59

1 उत्तर

सबसे बढ़िया उत्तर

आपकी समस्या मूल्यांकन और निष्पादन के बीच का अंतर है।

जब आप कुछ ऐसा लिखते हैं:

Console.log "foo"

आपके अंतर्ज्ञान के विपरीत, जो वास्तव में कंसोल पर कुछ भी प्रिंट नहीं करता है। इसके बजाय, यह एक "एक्शन" बनाता है, जिसे बाद में किसी बिंदु पर "निष्पादित" किया जाना है, और यह केवल तभी है कि यह कंसोल पर कुछ प्रिंट करेगा।

इसके विपरीत, एक ही क्रिया को वास्तव में कई बार "निष्पादित" किया जा सकता है, और इस प्रकार कई प्रभाव उत्पन्न होते हैं:

printFoo = Console.log "foo"
-- ^ Nothing is printed at this point

main = do
    printFoo
    printFoo
    printFoo
    -- ^ "foo" is printed three times
  • "मूल्यांकन" "कार्रवाई" बना रहा है
  • "निष्पादन" जो भी प्रभाव पैदा करता है उसे उत्पन्न करने के लिए "कार्रवाई" चला रहा है

उपरोक्त उदाहरण में, मूल्यांकन एक बार होता है, लेकिन निष्पादन - तीन बार।


जिस तरह से unless काम करता है, वह एक Boolean मान और एक "कार्रवाई" लेता है, और यह एक और "कार्रवाई" लौटाता है:

dontPrintFoo = unless true printFoo

जब आप dontPrintFoo क्रिया को निष्पादित करते हैं, तो यह जब तक द्वारा लौटाई गई क्रिया होगी, जो बूलियन पैरामीटर की जांच करेगी और नहीं करने के लिए चुनेंगी कार्रवाई printFoo निष्पादित करें।

लेकिन कहें कि आपके पास थोड़ा और जटिल परिदृश्य है:

dontPrintFoo = unless true $ if qux then printFoo else printBar

यहां, unless के दोनों पैरामीटरों को unless में पास करने से पहले "मूल्यांकन" (लेकिन "निष्पादित" नहीं) होना चाहिए। इसका अर्थ है कि qux के मान और if/then के परिणाम की गणना unless को कॉल करने से पहले की जाती है। लेकिन परिणामी कार्रवाई बाद में निष्पादित की जाएगी, जब पूरे परिणाम को main से बुलाया जाएगा।


लेकिन trace खास है। जादू। भले ही यह एक प्रभाव उत्पन्न करता है (कंसोल पर प्रिंटिंग), संकलक सोचता है कि यह एक शुद्ध कार्य है। 2 + 3 को पसंद करें या if qux then foo else bar को पसंद करें। यह डिबगिंग सुविधा के लिए इस तरह से किया गया है: ताकि आप शुद्ध, गैर-प्रभावी कोड में ट्रेसिंग सम्मिलित कर सकें।

इसका मतलब है कि trace का मूल्यांकन "मूल्यांकन" समय पर किया जाता है, न कि "निष्पादन" पर। इसका मतलब यह है कि इसका मूल्यांकन पहले unless से किया जाता है, और इसलिए इसका मूल्यांकन किया जाता है, भले ही Boolean पैरामीटर true हो या false


यदि आप चाहते हैं कि ट्रेसिंग केवल तभी काम करे जब unless ने कार्रवाई को अंजाम देने का फैसला किया, तो traceM आज़माएं:

unless (...) do
    traceM (show scrollDelta)
    foo
    bar
4
Fyodor Soikin 28 नवम्बर 2020, 01:52