জিএইচসি নির্ভরযোগ্যভাবে সঞ্চালনের জন্য কী অপ্টিমাইজেশন আশা করা যায়?


183

জিএইচসির প্রচুর পরিমাণে অপ্টিমাইজেশন রয়েছে যা এটি সম্পাদন করতে পারে, তবে আমি জানি না সেগুলি কী, এবং কীভাবে তারা সম্পাদন করার সম্ভাবনা রয়েছে এবং কী পরিস্থিতিতে।

আমার প্রশ্ন হ'ল প্রতিবারের প্রায়শই বা এর প্রায়শই কী রূপান্তরগুলি আমি প্রয়োগ করতে পারি? আমি যদি এমন কোনও কোডের টুকরোগুলি ঘন ঘন দেখি যা ঘন ঘন কার্যকর করা হবে (মূল্যায়ন করা) এবং আমার প্রথম চিন্তাটি "হুম, সম্ভবত আমার এটি অপ্টিমাইজ করা উচিত", যে ক্ষেত্রে আমার দ্বিতীয় চিন্তা হওয়া উচিত, "এটি সম্পর্কেও ভাবেন না, জিএইচসি পেয়েছে এই "?

আমি কাগজটি পড়ছিলাম স্ট্রিম ফিউশন: তালিকাগুলি থেকে স্ট্রিমিজ টু নথিং অল তেমন কিছুই নয় , এবং তারা পুনর্লিখনের তালিকা প্রক্রিয়াকরণকে অন্য পদ্ধতিতে ব্যবহার করেছিল যে কৌশলটি জিএইচসি-র সাধারণ অপ্টিমাইজেশানগুলি তখন সহজ লুপগুলিতে নির্ভরযোগ্যভাবে অপ্টিমাইজ করবে me আমি কীভাবে বলতে পারি যখন আমার নিজস্ব প্রোগ্রামগুলি সেই ধরণের অপ্টিমাইজেশনের জন্য যোগ্য?

আছে কিছু তথ্য GHC ম্যানুয়াল, কিন্তু এটি শুধুমাত্র প্রশ্নের উত্তর দিকে পথ অংশ চলে যায়।

সম্পাদনা: আমি একটি অনুগ্রহ শুরু করছি। আমি যা চাই তা হ'ল ল্যাম্বদা / লেট / কেস-ফ্লোটিং, টাইপ / কনস্ট্রাক্টর / ফাংশন আর্গুমেন্ট স্পেশালাইজেশন, কঠোরতা বিশ্লেষণ এবং আনবক্সিং, কর্মী / মোড়ক, এবং অন্য যে উল্লেখযোগ্য জিএইচসি আমাকে বাদ দিয়েছিল তার মতো নিম্ন স্তরের রূপান্তরগুলির একটি তালিকা , ইনপুট এবং আউটপুট কোডের ব্যাখ্যা এবং উদাহরণগুলির সাথে এবং যখন পরিস্থিতিগুলির সামগ্রীর প্রভাবের অংশের যোগফলের চেয়ে মোট প্রভাব বেশি হয় তখন আদর্শভাবে চিত্রের। এবং আদর্শভাবে কিছু উল্লেখ করুন যখন রূপান্তরগুলি ঘটবে নাঘটে। আমি প্রতিটি রূপান্তরের উপন্যাসের দৈর্ঘ্যের ব্যাখ্যা প্রত্যাশা করছি না, বেশ কয়েকটি বাক্য এবং ইনলাইন এক-লাইন কোড উদাহরণগুলি যথেষ্ট হতে পারে (বা কোনও লিঙ্ক, এটি যদি বৈজ্ঞানিক কাগজের বিশ পৃষ্ঠায় না হয়), যতক্ষণ না বড় চিত্র হয় এটি শেষ দ্বারা পরিষ্কার। আমি একটি কোডের টুকরোটি দেখতে সক্ষম হতে চাই এবং এটি একটি শক্ত লুপে সংকলন করবে কিনা, বা কেন হবে না বা এটি তৈরি করতে আমাকে কী পরিবর্তন করতে হবে সে সম্পর্কে একটি ভাল অনুমান করতে সক্ষম হতে চাই। (আমি এখানে স্ট্রিম ফিউশন এর মতো বড় অপ্টিমাইজেশনের কাঠামোগুলিতে এত আগ্রহী নই (আমি কেবল সে সম্পর্কে একটি কাগজ পড়েছি); এই ফ্রেমওয়ার্কগুলি লেখার লোকদের যে ধরণের জ্ঞান রয়েছে তা আরও বেশি ))


10
এটি একটি সর্বাধিক যোগ্য প্রশ্ন। উপযুক্ত উত্তর লেখা হ'ল ... ছদ্মবেশী।
গাণিতিক

1
সত্যিই ভাল সূচনা পয়েন্টটি হ'ল: aosabook.org/en/ghc.html
গ্যাব্রিয়েল গনজালেজ

7
যে কোনও ভাষায়, যদি আপনার প্রথম চিন্তাটি হয় "সম্ভবত আমার এটির অনুকূলতা নেওয়া উচিত," আপনার দ্বিতীয় চিন্তাটি "আমি প্রথমে এটির প্রোফাইল করব" be
জন এল

4
আপনি যে জ্ঞানটি পরে যাচ্ছেন তা সহায়ক, এবং তাই এটি এখনও একটি ভাল প্রশ্ন, আমি মনে করি আপনি যতটা সম্ভব কম অপ্টিমাইজেশন করার চেষ্টা করে সত্যই আরও ভালভাবে পরিবেশন করেছেন । লিখুন আপনি কি বলতে চাইছেন, এবং শুধুমাত্র যখন এটি হয়ে আপাত আপনি প্রয়োজন যে তারপর কর্মক্ষমতা অনুরোধে কোড কম সহজবোধ্য উপার্জন আমার মনে হয়। কোডটি দেখার চেয়ে এবং "এটি যে ঘন ঘন মৃত্যুদন্ড কার্যকর করা হবে, সম্ভবত আমার এটি অপ্টিমাইজ করা উচিত" এর পরিবর্তে, আপনি যখন কোডটি খুব ধীরে চলমান পর্যবেক্ষণ করছেন কেবল তখনই আপনার মনে হবে "ঘন ঘন মৃত্যুদন্ড কার্যকর করা উচিত এবং এটি অপ্টিমাইজ করা উচিত" ।
বেন

14
আমি সম্পূর্ণরূপে প্রত্যাশা করেছিলাম যে অংশটি "এটির প্রোফাইল দিন!" :)। তবে আমি অনুমান করি যে মুদ্রার অপর পক্ষটি হ'ল, যদি আমি এটির প্রোফাইল দিই এবং এটি ধীর হয়, তবে আমি আবার এটি লিখতে বা কেবল এমন একটি ফর্মের সাথে ঝাঁকুনি করতে পারি যা এখনও উচ্চ স্তরের তবে জিএইচসি নিজেই এটির হাত-আশা করার পরিবর্তে আরও ভাল করতে পারে? যার জন্য একই ধরণের জ্ঞান প্রয়োজন। এবং যদি আমার প্রথম জ্ঞানটি থাকে তবে আমি নিজেকে সম্পাদনা-চক্র সংরক্ষণ করতে পারতাম।
glaebhoerl

উত্তর:


110

এই জিএইচসি ট্র্যাক পৃষ্ঠাটি পাসগুলি মোটামুটিভাবে ভালভাবে ব্যাখ্যা করে। এই পৃষ্ঠাটি অপ্টিমাইজেশন অর্ডারটি ব্যাখ্যা করে, যদিও ট্র্যাক উইকের বেশিরভাগ অংশের মতো এটি পুরানো।

নির্দিষ্টকরণের জন্য, সর্বোত্তম কাজটি সম্ভবত কোনও নির্দিষ্ট প্রোগ্রাম কীভাবে সংকলিত হয় তা লক্ষ্য করা। কোনটি অপ্টিমাইজেশন করা হচ্ছে তা দেখার সেরা উপায়টি হ'ল -vপতাকাটি ব্যবহার করে শব্দটিকে ভার্চুয়ালভাবে সংকলন করা । উদাহরণ হিসাবে হ্যাস্কেলের প্রথম টুকরোটি আমি আমার কম্পিউটারে খুঁজে পেতে পারি:

Glasgow Haskell Compiler, Version 7.4.2, stage 2 booted by GHC version 7.4.1
Using binary package database: /usr/lib/ghc-7.4.2/package.conf.d/package.cache
wired-in package ghc-prim mapped to ghc-prim-0.2.0.0-7d3c2c69a5e8257a04b2c679c40e2fa7
wired-in package integer-gmp mapped to integer-gmp-0.4.0.0-af3a28fdc4138858e0c7c5ecc2a64f43
wired-in package base mapped to base-4.5.1.0-6e4c9bdc36eeb9121f27ccbbcb62e3f3
wired-in package rts mapped to builtin_rts
wired-in package template-haskell mapped to template-haskell-2.7.0.0-2bd128e15c2d50997ec26a1eaf8b23bf
wired-in package dph-seq not found.
wired-in package dph-par not found.
Hsc static flags: -static
*** Chasing dependencies:
Chasing modules from: *SleepSort.hs
Stable obj: [Main]
Stable BCO: []
Ready for upsweep
  [NONREC
      ModSummary {
         ms_hs_date = Tue Oct 18 22:22:11 CDT 2011
         ms_mod = main:Main,
         ms_textual_imps = [import (implicit) Prelude, import Control.Monad,
                            import Control.Concurrent, import System.Environment]
         ms_srcimps = []
      }]
*** Deleting temp files:
Deleting: 
compile: input file SleepSort.hs
Created temporary directory: /tmp/ghc4784_0
*** Checking old interface for main:Main:
[1 of 1] Compiling Main             ( SleepSort.hs, SleepSort.o )
*** Parser:
*** Renamer/typechecker:
*** Desugar:
Result size of Desugar (after optimization) = 79
*** Simplifier:
Result size of Simplifier iteration=1 = 87
Result size of Simplifier iteration=2 = 93
Result size of Simplifier iteration=3 = 83
Result size of Simplifier = 83
*** Specialise:
Result size of Specialise = 83
*** Float out(FOS {Lam = Just 0, Consts = True, PAPs = False}):
Result size of Float out(FOS {Lam = Just 0,
                              Consts = True,
                              PAPs = False}) = 95
*** Float inwards:
Result size of Float inwards = 95
*** Simplifier:
Result size of Simplifier iteration=1 = 253
Result size of Simplifier iteration=2 = 229
Result size of Simplifier = 229
*** Simplifier:
Result size of Simplifier iteration=1 = 218
Result size of Simplifier = 218
*** Simplifier:
Result size of Simplifier iteration=1 = 283
Result size of Simplifier iteration=2 = 226
Result size of Simplifier iteration=3 = 202
Result size of Simplifier = 202
*** Demand analysis:
Result size of Demand analysis = 202
*** Worker Wrapper binds:
Result size of Worker Wrapper binds = 202
*** Simplifier:
Result size of Simplifier = 202
*** Float out(FOS {Lam = Just 0, Consts = True, PAPs = True}):
Result size of Float out(FOS {Lam = Just 0,
                              Consts = True,
                              PAPs = True}) = 210
*** Common sub-expression:
Result size of Common sub-expression = 210
*** Float inwards:
Result size of Float inwards = 210
*** Liberate case:
Result size of Liberate case = 210
*** Simplifier:
Result size of Simplifier iteration=1 = 206
Result size of Simplifier = 206
*** SpecConstr:
Result size of SpecConstr = 206
*** Simplifier:
Result size of Simplifier = 206
*** Tidy Core:
Result size of Tidy Core = 206
writeBinIface: 4 Names
writeBinIface: 28 dict entries
*** CorePrep:
Result size of CorePrep = 224
*** Stg2Stg:
*** CodeGen:
*** CodeOutput:
*** Assembler:
'/usr/bin/gcc' '-fno-stack-protector' '-Wl,--hash-size=31' '-Wl,--reduce-memory-overheads' '-I.' '-c' '/tmp/ghc4784_0/ghc4784_0.s' '-o' 'SleepSort.o'
Upsweep completely successful.
*** Deleting temp files:
Deleting: /tmp/ghc4784_0/ghc4784_0.c /tmp/ghc4784_0/ghc4784_0.s
Warning: deleting non-existent /tmp/ghc4784_0/ghc4784_0.c
link: linkables are ...
LinkableM (Sat Sep 29 20:21:02 CDT 2012) main:Main
   [DotO SleepSort.o]
Linking SleepSort ...
*** C Compiler:
'/usr/bin/gcc' '-fno-stack-protector' '-Wl,--hash-size=31' '-Wl,--reduce-memory-overheads' '-c' '/tmp/ghc4784_0/ghc4784_0.c' '-o' '/tmp/ghc4784_0/ghc4784_0.o' '-DTABLES_NEXT_TO_CODE' '-I/usr/lib/ghc-7.4.2/include'
*** C Compiler:
'/usr/bin/gcc' '-fno-stack-protector' '-Wl,--hash-size=31' '-Wl,--reduce-memory-overheads' '-c' '/tmp/ghc4784_0/ghc4784_0.s' '-o' '/tmp/ghc4784_0/ghc4784_1.o' '-DTABLES_NEXT_TO_CODE' '-I/usr/lib/ghc-7.4.2/include'
*** Linker:
'/usr/bin/gcc' '-fno-stack-protector' '-Wl,--hash-size=31' '-Wl,--reduce-memory-overheads' '-o' 'SleepSort' 'SleepSort.o' '-L/usr/lib/ghc-7.4.2/base-4.5.1.0' '-L/usr/lib/ghc-7.4.2/integer-gmp-0.4.0.0' '-L/usr/lib/ghc-7.4.2/ghc-prim-0.2.0.0' '-L/usr/lib/ghc-7.4.2' '/tmp/ghc4784_0/ghc4784_0.o' '/tmp/ghc4784_0/ghc4784_1.o' '-lHSbase-4.5.1.0' '-lHSinteger-gmp-0.4.0.0' '-lgmp' '-lHSghc-prim-0.2.0.0' '-lHSrts' '-lm' '-lrt' '-ldl' '-u' 'ghczmprim_GHCziTypes_Izh_static_info' '-u' 'ghczmprim_GHCziTypes_Czh_static_info' '-u' 'ghczmprim_GHCziTypes_Fzh_static_info' '-u' 'ghczmprim_GHCziTypes_Dzh_static_info' '-u' 'base_GHCziPtr_Ptr_static_info' '-u' 'base_GHCziWord_Wzh_static_info' '-u' 'base_GHCziInt_I8zh_static_info' '-u' 'base_GHCziInt_I16zh_static_info' '-u' 'base_GHCziInt_I32zh_static_info' '-u' 'base_GHCziInt_I64zh_static_info' '-u' 'base_GHCziWord_W8zh_static_info' '-u' 'base_GHCziWord_W16zh_static_info' '-u' 'base_GHCziWord_W32zh_static_info' '-u' 'base_GHCziWord_W64zh_static_info' '-u' 'base_GHCziStable_StablePtr_static_info' '-u' 'ghczmprim_GHCziTypes_Izh_con_info' '-u' 'ghczmprim_GHCziTypes_Czh_con_info' '-u' 'ghczmprim_GHCziTypes_Fzh_con_info' '-u' 'ghczmprim_GHCziTypes_Dzh_con_info' '-u' 'base_GHCziPtr_Ptr_con_info' '-u' 'base_GHCziPtr_FunPtr_con_info' '-u' 'base_GHCziStable_StablePtr_con_info' '-u' 'ghczmprim_GHCziTypes_False_closure' '-u' 'ghczmprim_GHCziTypes_True_closure' '-u' 'base_GHCziPack_unpackCString_closure' '-u' 'base_GHCziIOziException_stackOverflow_closure' '-u' 'base_GHCziIOziException_heapOverflow_closure' '-u' 'base_ControlziExceptionziBase_nonTermination_closure' '-u' 'base_GHCziIOziException_blockedIndefinitelyOnMVar_closure' '-u' 'base_GHCziIOziException_blockedIndefinitelyOnSTM_closure' '-u' 'base_ControlziExceptionziBase_nestedAtomically_closure' '-u' 'base_GHCziWeak_runFinalizzerBatch_closure' '-u' 'base_GHCziTopHandler_flushStdHandles_closure' '-u' 'base_GHCziTopHandler_runIO_closure' '-u' 'base_GHCziTopHandler_runNonIO_closure' '-u' 'base_GHCziConcziIO_ensureIOManagerIsRunning_closure' '-u' 'base_GHCziConcziSync_runSparks_closure' '-u' 'base_GHCziConcziSignal_runHandlers_closure'
link: done
*** Deleting temp files:
Deleting: /tmp/ghc4784_0/ghc4784_1.o /tmp/ghc4784_0/ghc4784_0.s /tmp/ghc4784_0/ghc4784_0.o /tmp/ghc4784_0/ghc4784_0.c
*** Deleting temp dirs:
Deleting: /tmp/ghc4784_0

প্রথম *** Simplifier:থেকে শেষ অবধি যেখানে সমস্ত অপ্টিমাইজেশন পর্যায়গুলি ঘটে সেখানে আমরা বেশ কিছু দেখতে পাই।

প্রথমত, সিম্প্লিফায়ার প্রায় সমস্ত পর্যায়ের মধ্যে চলে runs এটি অনেকগুলি পাস করা সহজ করে তোলে। উদাহরণস্বরূপ, অনেকগুলি অপ্টিমাইজেশন প্রয়োগ করার সময়, এগুলি ম্যানুয়ালি না করে পরিবর্তনের প্রচার করার জন্য তারা কেবল পুনরায় লেখার নিয়ম তৈরি করে। সরলকরণকারী ইনলাইনিং এবং ফিউশন সহ বেশ কয়েকটি সহজ অপ্টিমাইজেশনকে অন্তর্ভুক্ত করে। আমি জানি এটির মূল সীমাবদ্ধতা হ'ল জিএইচসি পুনরাবৃত্ত ফাংশনগুলি ইনলাইন করতে অস্বীকার করেছে এবং ফিউশনকে কাজ করার জন্য জিনিসগুলির সঠিক নামকরণ করতে হবে।

এরপরে, আমরা সম্পাদিত সমস্ত অপ্টিমাইজেশনের একটি সম্পূর্ণ তালিকা দেখতে পাচ্ছি:

  • বিশেষজ্ঞ

    বিশেষায়নের প্রাথমিক ধারণাটি হ'ল ফাংশনটি যেখানে বলা হয় সেই জায়গাগুলি সনাক্ত করে বহুবর্ষ এবং ওভারলোডিং অপসারণ এবং বহুভুজ নয় এমন ফাংশনের সংস্করণ তৈরি করে - তারা যে ধরণের সাথে ডাকা হয় তার সাথে এটি নির্দিষ্ট। SPECIALISEসংকলককে প্রাগমা দিয়ে এটি করতে বলতে পারেন । উদাহরণ হিসাবে, একটি ফ্যাক্টরিয়াল ফাংশন নিন:

    fac :: (Num a, Eq a) => a -> a
    fac 0 = 1
    fac n = n * fac (n - 1)

    সংকলকটি যে গুণটি ব্যবহার করতে হবে তার কোনও বৈশিষ্ট্যই জানে না, এটি একেবারেই অনুকূলিত করতে পারে না। তবে এটি যদি এটি দেখতে পায় যে এটি কোনওটিতে ব্যবহৃত হয় তবে Intএটি এখন কেবল নতুন ধরণের ভিন্ন ভিন্ন একটি নতুন সংস্করণ তৈরি করতে পারে:

    fac_Int :: Int -> Int
    fac_Int 0 = 1
    fac_Int n = n * fac_Int (n - 1)

    এরপরে, নীচে উল্লিখিত নিয়মাবলী Intগুলি চালাতে পারে এবং আপনি আনবক্সডে কাজ করার কিছু শেষ করবেন যা মূলের চেয়ে অনেক দ্রুত। বিশেষায়নের দিকে নজর দেওয়ার আরেকটি উপায় হ'ল টাইপ শ্রেণির অভিধান এবং টাইপ ভেরিয়েবলগুলির উপর আংশিক প্রয়োগ।

    এখানকার উত্সটিতে এতে নোটের বোঝা রয়েছে।

  • ভাসা ভাসা

    সম্পাদনা: আমি স্পষ্টত আগে এটি ভুল বুঝেছি। আমার ব্যাখ্যা সম্পূর্ণরূপে পরিবর্তিত হয়েছে।

    এর মূল ধারণাটি হ'ল কম্পিউটেশনগুলি সরিয়ে নেওয়া যা ফাংশনগুলির বাইরে পুনরাবৃত্তি করা উচিত নয়। উদাহরণস্বরূপ, ধরুন আমাদের এটি ছিল:

    \x -> let y = expensive in x+y

    উপরের লাম্বদাতে, প্রতিটি সময় ফাংশনটি ডাকা হয়, yপুনরায় সংশোধন করা হয়। একটি ভাল ফাংশন, যা ভাসমান আউট উত্পাদন করে, তা

    let y = expensive in \x -> x+y

    প্রক্রিয়াটি সহজ করার জন্য, অন্যান্য রূপান্তরগুলি প্রয়োগ করা যেতে পারে। উদাহরণস্বরূপ, এটি ঘটে:

     \x -> x + f 2
     \x -> x + let f_2 = f 2 in f_2
     \x -> let f_2 = f 2 in x + f_2
     let f_2 = f 2 in \x -> x + f_2

    আবার, পুনরাবৃত্তি গণনা সংরক্ষণ করা হয়।

    এক্ষেত্রে উত্সটি খুব পঠনযোগ্য।

    এই মুহূর্তে দুটি সংলগ্ন ল্যাম্বডাসের মধ্যে বাইন্ডিংগুলি ভাসমান নয়। উদাহরণস্বরূপ, এটি ঘটে না:

    \x y -> let t = x+x in ...

    যাচ্ছি

     \x -> let t = x+x in \y -> ...
  • ভিতরে ভাসা

    উত্স কোডটি উদ্ধৃত করা,

    এর মূল উদ্দেশ্যটি floatInwardsএকটি মামলার শাখায় ভাসমান, যাতে আমরা জিনিসগুলি বরাদ্দ না করি, স্ট্যাকের মধ্যে সংরক্ষণ করি এবং তারপরে আবিষ্কার করতে পারি যে নির্বাচিত শাখায় তাদের প্রয়োজন নেই।

    উদাহরণ হিসাবে, ধরুন আমাদের এই অভিব্যক্তিটি ছিল:

    let x = big in
        case v of
            True -> x + 1
            False -> 0

    যদি vমূল্যায়ন করা হয় False, তবে বরাদ্দ দিয়ে x, যা সম্ভবত কিছু বড় থাঙ্ক, আমরা সময় এবং স্থান নষ্ট করেছি। ভাসমান অভ্যন্তরীণ স্থির করে দেয় এটি উত্পাদন করে:

    case v of
        True -> let x = big in x + 1
        False -> let x = big in 0

    যা পরবর্তীকালে সরলকরণকারী দ্বারা প্রতিস্থাপন করা হয়

    case v of
        True -> big + 1
        False -> 0

    এই কাগজটি , যদিও অন্যান্য বিষয়গুলি কভার করে, একটি মোটামুটি পরিষ্কার ভূমিকা দেয়। মনে রাখবেন যে তাদের নাম থাকা সত্ত্বেও, ভাসমান এবং ভাসমান দুটি কারণে দুটি অসীম লুপে পাবেন না:

    1. ভাসা-ভাসা ভাসা caseবিবৃতি দেয় , অন্যদিকে ফাংশন নিয়ে কাজ করে deals
    2. পাসগুলির একটি স্থির ক্রম রয়েছে, সুতরাং এগুলি অনন্তর পরিবর্তিত হওয়া উচিত নয়।

  • চাহিদা বিশ্লেষণ

    চাহিদা বিশ্লেষণ বা কঠোরতার বিশ্লেষণ কোনও রূপান্তর কম হয় এবং নাম যেমন প্রস্তাবিত হয় তথ্য সংগ্রহের পাসের মতো। সংকলকটি এমন ফাংশনগুলি সন্ধান করে যা সর্বদা তাদের যুক্তিগুলি মূল্যায়ন করে (বা তাদের মধ্যে কমপক্ষে কিছু) এবং কল-বাই-মান ব্যবহার করে কল-বাই-মান ব্যবহার করে সেই যুক্তিগুলি পাস করে। যেহেতু আপনি থাঙ্কগুলির ওভারহেডগুলি এড়ানোর জন্য পান তাই এটি প্রায়শই দ্রুত হয়। হাস্কেলের পারফরম্যান্সের অনেকগুলি সমস্যা এই পাসটি ব্যর্থ হয়, বা কোড কেবল পর্যাপ্ত কঠোর না হয়ে থাকে arise একটি উত্তম উদাহরণ ব্যবহার মধ্যে পার্থক্য foldr, foldlএবংfoldl'পূর্ণসংখ্যার একটি তালিকা যোগফল - প্রথমটি স্ট্যাকের ওভারফ্লো কারণ, দ্বিতীয়টি হিপ ওভারফ্লো কারণ এবং শেষেরটি সূক্ষ্ম রান, কারণ কঠোরতার কারণে। এইগুলি বোঝার জন্য এটি সম্ভবত সবচেয়ে সহজ এবং সর্বোত্তম নথিভুক্ত। আমি বিশ্বাস করি যে পলিমারফিজম এবং সিপিএস কোড প্রায়শই এটিকে পরাজিত করে।

  • শ্রমিক আবরণ বাঁধে

    কর্মী / মোড়ক রূপান্তরের মূল ধারণাটি হ'ল একটি সাধারণ কাঠামোর উপর একটি আঁট লুপ করা, সেই কাঠামোটির শেষ প্রান্তে এবং থেকে রূপান্তর করা। উদাহরণস্বরূপ, এই ফাংশনটি ধরুন, যা একটি সংখ্যার ফ্যাকটোরিয়াল গণনা করে।

    factorial :: Int -> Int
    factorial 0 = 1
    factorial n = n * factorial (n - 1)

    Intজিএইচসি- র সংজ্ঞা ব্যবহার করে আমাদের আছে

    factorial :: Int -> Int
    factorial (I# 0#) = I# 1#
    factorial (I# n#) = I# (n# *# case factorial (I# (n# -# 1#)) of
        I# down# -> down#)

    লক্ষ্য করুন যে কোডটি কীভাবে in I#াকা যায়? এটি করে আমরা এগুলি সরাতে পারি:

    factorial :: Int -> Int
    factorial (I# n#) = I# (factorial# n#)
    
    factorial# :: Int# -> Int#
    factorial# 0# = 1#
    factorial# n# = n# *# factorial# (n# -# 1#)

    যদিও এই সুনির্দিষ্ট উদাহরণটি স্পেসকনস্ট্রার দ্বারাও করা যেত, কর্মী / মোড়ক রূপান্তর এটি যে কাজগুলি করতে পারে তার মধ্যে খুব সাধারণ।

  • সাধারণ উপ-এক্সপ্রেশন

    এটি আর একটি সত্যই সহজ অপ্টিমাইজেশন যা অত্যন্ত কার্যকর, যেমন কঠোরতার বিশ্লেষণ। মূল ধারণাটি হ'ল যদি আপনার দুটি মত প্রকাশ হয় যা একই হয় তবে তাদের মান একই হবে। উদাহরণস্বরূপ, যদি fibএকটি ফিবোনাচি নম্বর ক্যালকুলেটর হয় তবে সিএসই রূপান্তর করবে

    fib x + fib x

    মধ্যে

    let fib_x = fib x in fib_x + fib_x

    অর্ধেক গণনা কেটে দেয় যা। দুর্ভাগ্যক্রমে, এটি মাঝে মধ্যে অন্যান্য অপ্টিমাইজেশনের পথে আসতে পারে। আর একটি সমস্যা হ'ল দুটি এক্সপ্রেশন একই জায়গায় থাকতে হবে এবং এগুলি সিনথেটিকভাবে একই হতে হবে , মান অনুসারে এক নয়। উদাহরণস্বরূপ, সিএসই নীচে কোডগুলিতে ইনলাইনিংয়ের গোছা ছাড়াই আগুন দেবে না:

    x = (1 + (2 + 3)) + ((1 + 2) + 3)
    y = f x
    z = g (f x) y

    তবে, আপনি যদি এলএলভিএমের মাধ্যমে সংকলন করেন, তবে এর গ্লোবাল মান সংখ্যায়ন পাসের কারণে আপনি এর কিছু সংযুক্ত পেতে পারেন।

  • মুক্তি মামলা

    এটি কোড বিস্ফোরণের কারণ হতে পারে তা ছাড়াও এটি একটি ভয়াবহ ডকুমেন্টেড রূপান্তর বলে মনে হচ্ছে। এখানে পাওয়া ছোট্ট ডকুমেন্টেশনের একটি পুনরায় ফর্ম্যাট করা (এবং কিছুটা নতুন করে লেখা) সংস্করণ এখানে রয়েছে:

    এই মডিউলটি চলতে পারে Coreএবং caseবিনামূল্যে ভেরিয়েবলগুলি সন্ধান করে। মাপদণ্ডটি হ'ল: যদি caseপুনরাবৃত্তির কলটিতে রুটে কোনও ফ্রি ভেরিয়েবল থাকে, তবে পুনরাবৃত্ত কলটি একটি উদ্ঘাটন দ্বারা প্রতিস্থাপন করা হবে। উদাহরণস্বরূপ, ইন

    f = \ t -> case v of V a b -> a : f t

    অভ্যন্তর fপ্রতিস্থাপন করা হয়। করা

    f = \ t -> case v of V a b -> a : (letrec f = \ t -> case v of V a b -> a : f t in f) t

    ছায়ার জন্য প্রয়োজনীয়তা নোট করুন। সরলকরণ, আমরা পেয়েছি

    f = \ t -> case v of V a b -> a : (letrec f = \ t -> a : f t in f t)

    এটি আরও ভাল কোড, কারণ প্রজেকশন প্রয়োজনের চেয়ে aঅভ্যন্তরের অভ্যন্তরে letrecমুক্ত v। নোট করুন যে এটি স্পেসকনস্ট্রারের বিপরীতে ফ্রি ভেরিয়েবলগুলির সাথে সম্পর্কিত , যা জ্ঞাত রূপগুলির যুক্তিগুলির সাথে ডিল করে ।

    স্পেসকনস্ট্র্ট সম্পর্কে আরও তথ্যের জন্য নীচে দেখুন।

  • স্পেসকনস্ট্র - এটি প্রোগ্রামগুলিকে রূপান্তর করে

    f (Left x) y = somthingComplicated1
    f (Right x) y = somethingComplicated2

    মধ্যে

    f_Left x y = somethingComplicated1
    f_Right x y = somethingComplicated2
    
    {-# INLINE f #-}
    f (Left x) = f_Left x
    f (Right x) = f_Right x

    বর্ধিত উদাহরণ হিসাবে, এই সংজ্ঞাটি গ্রহণ করুন last:

    last [] = error "last: empty list"
    last (x:[]) = x
    last (x:x2:xs) = last (x2:xs)

    আমরা প্রথমে এটি রূপান্তর করি

    last_nil = error "last: empty list"
    last_cons x [] = x
    last_cons x (x2:xs) = last (x2:xs)
    
    {-# INLINE last #-}
    last [] = last_nil
    last (x : xs) = last_cons x xs

    এর পরে, সরলকরণকারী চলে এবং আমাদের আছে

    last_nil = error "last: empty list"
    last_cons x [] = x
    last_cons x (x2:xs) = last_cons x2 xs
    
    {-# INLINE last #-}
    last [] = last_nil
    last (x : xs) = last_cons x xs

    নোট করুন যে প্রোগ্রামটি এখন আমরা আরও দ্রুত করছি, কারণ আমরা বারবার তালিকার সামনের দিকে বক্সিং এবং আনবক্সিং করছি না। এছাড়াও নোট করুন যে ইনলাইনিংটি অত্যন্ত গুরুত্বপূর্ণ, কারণ এটি নতুন, আরও কার্যকর সংজ্ঞাগুলিকে প্রকৃতপক্ষে ব্যবহার করতে দেয় এবং পাশাপাশি পুনরাবৃত্ত সংজ্ঞাগুলি আরও ভাল করে তোলে।

    স্পেসকনস্ট্র অনেকগুলি হিউরিস্টিক দ্বারা নিয়ন্ত্রিত হয়। কাগজে যেগুলি উল্লিখিত হয়েছে সেগুলি হ'ল:

    1. ল্যাম্বডাস স্পষ্ট এবং আধ্যাত্মিক হয় a
    2. ডান হাতটি "পর্যাপ্ত পরিমাণে ছোট", যা কিছু পতাকা দ্বারা নিয়ন্ত্রিত হয়।
    3. ফাংশনটি পুনরাবৃত্ত হয় এবং বিশেষ কলটি ডানদিকে ব্যবহৃত হয় is
    4. ফাংশনটিতে সমস্ত যুক্তি উপস্থিত রয়েছে।
    5. কমপক্ষে একটি যুক্তি একটি কনস্ট্রাক্টর অ্যাপ্লিকেশন।
    6. সেই যুক্তিটি ফাংশনের কোথাও কেস-বিশ্লেষণ করা হয়।

    তবে হিউরিস্টিকস প্রায় অবশ্যই পরিবর্তিত হয়েছে। প্রকৃতপক্ষে, কাগজটিতে একটি বিকল্প ষষ্ঠ তাত্পর্যপূর্ণ উল্লেখ রয়েছে:

    একটি আর্গুমেন্ট উপর বিশেষজ্ঞ xশুধুমাত্র যদি xহয় শুধুমাত্র একটি দ্বারা যাচাই-বাছাই case, এবং একটি সাধারণ ফাংশন প্রেরণ করা হয় না, বা ফলাফলের অংশ হিসেবে ফিরে আসেন।

এটি একটি খুব ছোট ফাইল (12 লাইন) এবং সম্ভবত এতগুলি অপ্টিমাইজেশানগুলি ট্রিগার করতে পারেনি (যদিও আমি মনে করি এটি এগুলি সব করেছিল)। এটি আপনাকে জানায় না যে এটি কেন এই পাসগুলি বাছাই করেছে এবং কেন তাদের সেই ক্রমে রেখেছিল।


এখন আমরা কোথাও পাচ্ছি! মন্তব্যসমূহ: আপনার কাছে বিশেষজ্ঞ সম্পর্কে অংশে একটি কাটা বাক্য আছে বলে মনে হচ্ছে। আমি ভাসমান আউট এর বিন্দু দেখতে পাচ্ছি না: এটা কিসের জন্য? এটি কীভাবে সিদ্ধান্ত নেবে যে ভাসমান হবে বা বাইরে (কেন এটি কোনও লুপে যায় না)? কোথাও থেকে ছাপ ছিল যে GHC সিএসই করিনি এ সব , কিন্তু দৃশ্যত যে ভুল ছিল না। আমার মনে হচ্ছে আমি বড় ছবি দেখার পরিবর্তে বিশদে হারিয়ে যাচ্ছি ... বিষয়টি আমার ধারণা থেকে আরও জটিল। হতে পারে আমার প্রশ্নটি অসম্ভব এবং এক টন অভিজ্ঞতা বা নিজে নিজে জিএইচসিতে কাজ করা ছাড়া এই স্বজ্ঞাততা লাভ করার কোনও উপায় নেই?
glaebhoerl

ঠিক আছে, আমি জানি না, তবে আমি কখনও জিএইচসি-তে কাজ করি নি, তাই আপনাকে অবশ্যই কিছুটা অন্তর্দৃষ্টি পেতে সক্ষম হতে হবে ।
গিরিটার

আপনার উল্লিখিত বিষয়গুলি আমি স্থির করেছি।
গিরিটার

1
এছাড়াও, বড় ছবি সম্পর্কে, এটি আমার মতামত যে সত্যিই একটি নেই। যখন আমি অনুমান করতে চাই যে কোনটি অপ্টিমাইজেশন করা হবে, আমি একটি চেকলিস্টে নেমে যাই। তারপরে আমি আবার এটি করি, প্রতিটি পাস কীভাবে জিনিসগুলিকে পরিবর্তন করবে তা দেখতে। এবং আবার. মূলত, আমি সংকলকটি খেলি। আমি জানি যে কেবলমাত্র অপটিমাইজেশন স্কিমটিই সত্যই একটি "বড় ছবি" সুপারকম্পিলেশন।
গিরিটার

1
"ফিউশন কাজ করার জন্য জিনিসগুলির সঠিক নামকরণ করতে হবে" এর অর্থ কী?
ভিনসেন্ট বেফারা

65

আলস্য

এটি একটি "সংকলক অপ্টিমাইজেশন" নয়, তবে এটি ভাষা স্পেসিফিকেশন দ্বারা গ্যারান্টিযুক্ত এমন কিছু, যাতে আপনি সর্বদা এটির উপর নির্ভর করতে পারেন। মূলত, এর অর্থ হল যে ফলাফলটি আপনি "কিছু না করা" না হওয়া পর্যন্ত কাজ করা হয় না। (যদি না আপনি ইচ্ছাকৃতভাবে অলসতা বন্ধ করার জন্য কয়েকটি কাজ না করেন))

এটি অবশ্যই স্পষ্টতই একটি নিজস্ব বিষয় এবং এটির বিষয়ে ইতিমধ্যে প্রচুর প্রশ্নোত্তর রয়েছে।

আমার সীমিত অভিজ্ঞতায়, আপনার কোডটি খুব অলস বা খুব কঠোর করে তোলার বিষয়ে আমি কথা বলার মতো অন্য যে কোনও স্টাফের তুলনায় (সময় এবং স্থানের ক্ষেত্রে) বিশাল আকারের পারফরম্যান্স পেনাল্টি পেয়েছি ...

কঠোরতা বিশ্লেষণ

অলসতা প্রয়োজনীয়তা না থাকলে কাজ এড়ানো সম্পর্কে। যদি সংকলক নির্ধারণ করতে পারে যে প্রদত্ত ফলাফলটি "সর্বদা" প্রয়োজন হবে, তবে এটি গণনাটি সংরক্ষণ এবং পরে সম্পাদনকে বিরক্ত করবে না; এটি কেবল এটি সম্পাদন করবে, কারণ এটি আরও দক্ষ। এটি তথাকথিত "কঠোরতা বিশ্লেষণ"।

স্পষ্টতই, গোচা হ'ল কম্পাইলারটি সর্বদা সনাক্ত করতে পারে না যে কখন কোনও কিছু কঠোর করা যায়। কখনও কখনও আপনাকে সংকলকটিকে সামান্য ইঙ্গিত দেওয়া দরকার। (কোর আউটপুটটি ভ্যাডিং বাদে কঠোরতা বিশ্লেষণ আপনার যা মনে হয়েছে তা করেছে কিনা তা নির্ধারণের কোনও সহজ উপায় সম্পর্কে আমি অবগত নই।)

ইনলাইনিং

আপনি যদি কোনও ফাংশন কল করেন এবং সংকলকটি আপনাকে বলতে পারে যে আপনি কোন ফাংশনটি কল করছেন, এটি সেই ফাংশনটির "ইনলাইন" করার চেষ্টা করতে পারে - এটি ফাংশনের কলটিকে নিজেই একটি অনুলিপি দিয়ে প্রতিস্থাপন করতে পারে। একটি ফাংশন কলের ওভারহেড সাধারণত খুব ছোট হয় তবে ইনলাইনিং প্রায়শই অন্যান্য অপটিমাইজেশনগুলিকে সক্ষম করে যা অন্যথায় ঘটে না, তাই ইনলাইনিং একটি বড় জয় হতে পারে।

যদি সেগুলি "যথেষ্ট পরিমাণে ছোট" হয় তবেই (বা আপনি যদি বিশেষত ইনলাইনিংয়ের জন্য জিজ্ঞাসাবাদ যুক্ত করেন) তবে কার্যাদি কেবল ইনলাইন করা হয়। এছাড়াও, ফাংশনগুলি কেবল তখনই ইনলাইন করা যেতে পারে যদি সংকলকটি আপনাকে বলতে পারে যে ফাংশনটি কল করছেন। দুটি প্রধান উপায় আছে যা সংকলকটি বলতে অক্ষম হতে পারে:

  • আপনি যে ফাংশনটি কল করছেন সেটি যদি অন্য কোথাও থেকে পাস করা হয়। উদাহরণস্বরূপ, filterফাংশনটি সংকলিত হয়ে গেলে আপনি ফিল্টার প্রিকিকেট ইনলাইন করতে পারবেন না, কারণ এটি একটি ব্যবহারকারী সরবরাহিত যুক্তি।

  • যদি আপনি যে ফাংশনটি কল করছেন সেটি কোনও শ্রেণিবদ্ধ পদ্ধতি এবং সংকলকটি কী প্রকারের সাথে জড়িত তা জানেন না। উদাহরণস্বরূপ, sumফাংশনটি সংকলিত হয়ে গেলে , সংকলকটি +ফাংশনটি ইনলাইন করতে পারে না , কারণ sumবিভিন্ন সংখ্যার ধরণের সাথে কাজ করে, যার প্রত্যেকটির একটি আলাদা +ফাংশন রয়েছে।

পরবর্তী ক্ষেত্রে, আপনি {-# SPECIALIZE #-}প্রাগমা ব্যবহার করতে পারেন কোনও নির্দিষ্ট ধরণের হার্ড-কোডড এমন কোনও ফাংশনের সংস্করণ তৈরি করতে। উদাহরণস্বরূপ, প্রকারের জন্য হার্ড {-# SPECIALIZE sum :: [Int] -> Int #-}কোডিংয়ের একটি সংস্করণ সংকলন করবে , যার অর্থ এই সংস্করণে অন্তর্ভুক্ত করা যেতে পারে।sumInt+

নোট করুন, যদিও, আমাদের নতুন বিশেষ sumফাংশনটি কেবল তখনই ডাকা হবে যখন সংকলক বলতে পারবে যে আমরা কাজ করছি Int। অন্যথায় আসল, পলিমারফিক sumবলা হয়। আবার, আসল ফাংশন কল ওভারহেড মোটামুটি ছোট। এটি অতিরিক্ত অপটিমাইজেশন যা ইনলাইনিং সক্ষম করে যা উপকারী।

প্রচলিত subexpression নির্মূল

কোডের একটি নির্দিষ্ট ব্লক যদি একই মানকে দুবার গণনা করে তবে সংকলক একই সংখ্যার একক উদাহরণ দিয়ে প্রতিস্থাপন করতে পারে। উদাহরণস্বরূপ, যদি আপনি করেন

(sum xs + 1) / (sum xs + 2)

তারপরে সংকলক এটি এটিকে অনুকূল করতে পারে

let s = sum xs in (s+1)/(s+2)

আপনি আশা করতে পারেন যে সংকলকটি সর্বদা এটি করবে । তবে আপাতদৃষ্টিতে কিছু পরিস্থিতিতে এর খারাপ পরিণতি হতে পারে, আরও ভাল নয়, তাই GHC সর্বদা এটি করে না । সত্যই, আমি এর পিছনে বিশদটি সত্যই বুঝতে পারি না। তবে নীচের অংশটি হ'ল, যদি এই রূপান্তরটি আপনার পক্ষে গুরুত্বপূর্ণ হয় তবে ম্যানুয়ালি এটি করা কঠিন নয়। (এবং যদি এটি গুরুত্বপূর্ণ না হয় তবে আপনি কেন এটি নিয়ে উদ্বিগ্ন হন?)

কেস এক্সপ্রেশন

নিম্নোক্ত বিবেচনা কর:

foo (0:_ ) = "zero"
foo (1:_ ) = "one"
foo (_:xs) = foo xs
foo (  []) = "end"

প্রথম তিনটি সমীকরণ সমস্ত তালিকাটি খালি নয় কিনা (অন্যান্য জিনিসের মধ্যে) পরীক্ষা করে। তবে তিনবার একই জিনিস পরীক্ষা করা ব্যর্থ। ভাগ্যক্রমে, সংকলকটির পক্ষে এটি বেশ কয়েকটি নেস্টেড কেস এক্সপ্রেশনগুলিতে অনুকূলিত করা খুব সহজ। এই ক্ষেত্রে, মত কিছু

foo xs =
  case xs of
    y:ys ->
      case y of
        0 -> "zero"
        1 -> "one"
        _ -> foo ys
    []   -> "end"

এটি বরং স্বল্পতর স্বজ্ঞাত, তবে আরও দক্ষ। যেহেতু সংকলক সহজেই এই রূপান্তরটি করতে পারে, আপনার এটি নিয়ে চিন্তা করার দরকার নেই। সর্বাধিক স্বজ্ঞাত উপায়ে আপনার প্যাটার্নের মিলটি কেবল লিখুন; এটিকে যত তাড়াতাড়ি করা যায় তার জন্য সংকলকটি এর পুনঃক্রম এবং পুনঃব্যবস্থাপনে খুব ভাল।

একীকরণ

তালিকা প্রক্রিয়াকরণের জন্য স্ট্যান্ডার্ড হাস্কেল আইডিয়ম হ'ল ফাংশনগুলি একসাথে চেইন করা যা একটি তালিকা নিয়ে এবং একটি নতুন তালিকা তৈরি করে। ক্যানোনিকাল উদাহরণ হচ্ছে

map g . map f

দুর্ভাগ্যক্রমে, অলসতা যখন অপ্রয়োজনীয় কাজগুলি এড়িয়ে যাওয়ার নিশ্চয়তা দেয়, তখন মধ্যবর্তী তালিকার এসএপি কর্মক্ষমতা জন্য সমস্ত বরাদ্দ এবং বিলোপ। "ফিউশন" বা "বনভূমি" যেখানে সংকলক এই মধ্যবর্তী পদক্ষেপগুলি মুছে ফেলার চেষ্টা করে।

সমস্যাটি হচ্ছে, এই ফাংশনগুলির বেশিরভাগই পুনরাবৃত্ত হয়। পুনরাবৃত্তি ছাড়াই, এটি সমস্ত ফাংশনকে একটি বড় কোড ব্লকে স্কোয়াশ করা, তার উপর সরলীকরণকারী চালানো এবং কোনও মধ্যবর্তী তালিকা ছাড়াই সত্যিকারের অনুকূল কোড উত্পাদন করা ইনলাইনিংয়ের প্রাথমিক অনুশীলন হবে। তবে পুনরাবৃত্তি হওয়ার কারণে এটি কার্যকর হবে না।

এর {-# RULE #-}কয়েকটি ঠিক করার জন্য আপনি প্রাগমাস ব্যবহার করতে পারেন । উদাহরণ স্বরূপ,

{-# RULES "map/map" forall f g xs. map f (map g xs) = map (f.g) xs #-}

এখন প্রতিবার জিএইচসি mapআবেদন করে দেখলে mapএটি মধ্যবর্তী তালিকাটি বাদ দিয়ে তালিকার একক পাসে এটিকে স্কোয়াশ করে।

সমস্যা হচ্ছে, এটি কেবল mapঅনুসরণের জন্য কাজ করে map। - অনেক অন্যান্য সম্ভাবনা আছে mapদ্বারা অনুসরণ filter, filterদ্বারা অনুসরণ map, ইত্যাদি বরং হাতে কোড তাদের প্রতিটি জন্য একটি সমাধান, তথাকথিত "স্ট্রিম লয়" আবিষ্কৃত হয়। এটি আরও জটিল কৌশল, যা আমি এখানে বর্ণনা করব না।

এর দীর্ঘ এবং সংক্ষিপ্তটি হ'ল: এগুলি প্রোগ্রামার দ্বারা রচিত সমস্ত বিশেষ অপ্টিমাইজেশনের কৌশল । জিএইচসি নিজেই ফিউশন সম্পর্কে কিছুই জানে না; এটি সমস্ত তালিকা গ্রন্থাগার এবং অন্যান্য ধারক লাইব্রেরিতে রয়েছে। সুতরাং কী কী অপ্টিমাইজেশান ঘটে তা নির্ভর করে কীভাবে আপনার ধারক লাইব্রেরিগুলি লেখা হয় (বা আরও বাস্তবসম্মতভাবে আপনি কোন লাইব্রেরিগুলি ব্যবহার করতে চান) তার উপর নির্ভর করে।

উদাহরণস্বরূপ, যদি আপনি হাস্কেল '98 অ্যারে নিয়ে কাজ করেন তবে কোনও প্রকারের কোনও ফিউশন আশা করবেন না। তবে আমি বুঝতে পারি যে vectorলাইব্রেরির বিস্তীর্ণ ফিউশন ক্ষমতা রয়েছে। এটি সমস্ত গ্রন্থাগার সম্পর্কে; সংকলক কেবল RULESপ্রগমা সরবরাহ করে । (যা অত্যন্ত শক্তিশালী, যাইহোক। একটি গ্রন্থাগারের লেখক হিসাবে, আপনি এটি ক্লায়েন্ট কোডটি পুনরায় লেখার জন্য ব্যবহার করতে পারেন!)


meta:

  • আমি "কোডটি প্রথম, প্রোফাইল দ্বিতীয়, তৃতীয়টিকে অনুকূলিতকরণ" বলার সাথে সম্মত agree

  • আমি লোকদের সাথেও একমত হয়ে বলি "প্রদত্ত ডিজাইনের সিদ্ধান্তের জন্য কতটা ব্যয় হয়েছে তার মানসিক মডেল রাখাই দরকারী"।

সমস্ত কিছুর মধ্যে ভারসাম্য, এবং ...


9
it's something guaranteed by the language specification ... work is not performed until you "do something" with the result.- বেপারটা এমন না. ভাষা বৈশিষ্ট্য অ-কঠোর শব্দার্থবিজ্ঞানের প্রতিশ্রুতি দেয় ; এটি অতিমাত্রায় কাজ করা হবে কিনা তা নিয়ে কোনও প্রতিশ্রুতি দেয় না।
ড্যান বার্টন

1
@ ড্যানবার্টন শিওর তবে এটি কয়েকটি বাক্যে ব্যাখ্যা করা আসল সহজ নয়। এছাড়াও, যেহেতু জিএইচসি প্রায় একমাত্র বিদ্যমান হাস্কেল বাস্তবায়ন, তাই জিএইচসি অলস হওয়ার বিষয়টি বেশিরভাগ মানুষের পক্ষে যথেষ্ট ভাল।
গাণিতিক

@ গণিতের অর্কিড: অনুমানমূলক মূল্যায়ন একটি আকর্ষণীয় প্রতিবিম্বিত উদাহরণ, যদিও আমি এটি সম্মত করি তবে এটি সম্ভবত কোনও নবজাতকের পক্ষে খুব বেশি।
বেন মিলউড

5
সিএসই সম্পর্কে: আমার ধারণাটি এটি প্রায়শই কখনও হয় নি, কারণ এটি অযাচিত ভাগ করে নেওয়া এবং তাই স্পেসলিক্সের পরিচয় দিতে পারে।
জোচিম ব্রেটনার

2
(ক) এখন আগে উত্তর না দেওয়ার জন্য এবং (খ) আপনার উত্তর গ্রহণ না করার জন্য দুঃখিত। যা দীর্ঘ এবং চিত্তাকর্ষক, তবে আমি যে অঞ্চলটি চেয়েছিলাম তা জুড়ে না। আমি যা চাই তা হ'ল ল্যাম্বদা / লেট / কেস-ফ্লোটিং, টাইপ / কনস্ট্রাক্টর / ফাংশন আর্গুমেন্ট স্পেশালাইজেশন, কঠোরতা বিশ্লেষণ এবং আনবক্সিং (যা আপনি উল্লেখ করেছেন), কর্মী / মোড়ক এবং অন্য কোনও জিএইচসি, পাশাপাশি যা করে তা নিম্ন স্তরের রূপান্তরগুলির একটি তালিকা is ইনপুট এবং আউটপুট কোডের ব্যাখ্যা এবং উদাহরণ সহ এবং তাদের সম্মিলিত প্রভাবের উদাহরণ এবং উদাহরণ যেখানে রূপান্তর ঘটে না । আমি অনুমান করি আমার কি অনুগ্রহ করা উচিত?
glaebhoerl

8

যদি একটি লেট বাঁধাই করা ভি = আরএইচ কেবলমাত্র এক জায়গায় ব্যবহার করা হয় তবে আপনি আরএইচএস বড় হলেও এর ইনলাইন করতে সংকলকটির উপর নির্ভর করতে পারেন।

ব্যতিক্রম (এটি বর্তমান প্রশ্নের প্রসঙ্গে প্রায় এক নয়) লম্বডাস হ'ল ঝুঁকিপূর্ণ কাজের নকল। বিবেচনা:

let v = rhs
    l = \x-> v + x
in map l [1..100]

সেখানে ইনলাইনিং ভি বিপজ্জনক হবে কারণ এক (সিনট্যাকটিক) ব্যবহারটি আরএসএসের 99 টি অতিরিক্ত মূল্যায়নে অনুবাদ করবে। যাইহোক, এই ক্ষেত্রে, আপনি নিজে নিজে এটির সাথে ইনলাইন করতে চান না খুব সম্ভবত। সুতরাং মূলত আপনি নিয়মটি ব্যবহার করতে পারেন:

আপনি যদি একবারে কেবল এমন একটি নাম অন্তর্ভুক্ত করার বিষয়টি বিবেচনা করেন তবে সংকলক যেকোনভাবে তা করবে।

একটি সুখী করোলারি হিসাবে, একটি দীর্ঘ বিবৃতিটি (স্পষ্টতা পাওয়ার আশা নিয়ে) পচে যাওয়ার জন্য কেবল একটি বাঁধাই ব্যবহার করা মূলত বিনামূল্যে।

এটি সম্প্রদায়টি থেকে এসেছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.