Clojure: হ্রাস বনাম প্রয়োগ


126

আমি বুঝতে পারছি মধ্যে ধারণাগত পার্থক্য reduceএবং apply:

(reduce + (list 1 2 3 4 5))
; translates to: (+ (+ (+ (+ 1 2) 3) 4) 5)

(apply + (list 1 2 3 4 5))
; translates to: (+ 1 2 3 4 5)

যাইহোক, কোনটি আরও মূর্তিমান ক্লোজার? এটি কি এক উপায়ে বা অন্যভাবে অনেক পার্থক্য আনতে পারে? আমার (সীমাবদ্ধ) পারফরম্যান্স পরীক্ষা থেকে মনে reduceহচ্ছে এটি কিছুটা দ্রুত faster

উত্তর:


125

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

+reduceভেরিয়েবল-আরটি মামলার ক্ষেত্রে (2 টিরও বেশি আর্গুমেন্ট) নিজেই প্রয়োগ করা হয় । প্রকৃতপক্ষে, এটি কোনও পরিবর্তনশীল-আধ্যাত্মিকতা, সহযোগী ক্রিয়াকলাপের reduceপক্ষে যাওয়ার মতো এক বিস্ময়কর "ডিফল্ট" উপায়ের মতো বলে মনে হচ্ছে: জিনিসগুলিকে গতি বাড়ানোর জন্য কিছু আশাবাদী করার সম্ভাবনা রয়েছে - সম্ভবত এমন কিছু মাধ্যমে যা internal-reduceসম্প্রতি একটি মাস্টার হিসাবে অক্ষম হয়েছে, তবে আশা করি ভবিষ্যতে পুনরায় প্রবর্তন হবে - যা ভার্জ ক্ষেত্রে তাদের থেকে উপকৃত হতে পারে এমন প্রতিটি ফাংশনে প্রতিলিপি দেওয়া মূর্খতা হবে। এই ধরনের সাধারণ ক্ষেত্রে, applyকেবলমাত্র একটি সামান্য ওভারহেড যুক্ত করবে। (নোট করুন এটি সম্পর্কে সত্যই উদ্বিগ্ন হওয়ার কিছু নেই))

অন্যদিকে, একটি জটিল ক্রিয়াকলাপটি কিছু অপ্টিমাইজেশান সুযোগগুলির সুবিধা নিতে পারে যা সাধারণভাবে তৈরি করা যায় না reduce; তাহলে applyআপনাকে সেগুলির সুবিধা নিতে দেওয়া হবে যখন reduceসম্ভবত আপনাকে ধীর করে দেবে। অনুশীলনের ক্ষেত্রে পরবর্তী ঘটনাগুলির একটি উত্তম উদাহরণ সরবরাহ করেছেন str: এটি StringBuilderঅভ্যন্তরীণভাবে ব্যবহার করে এবং এর applyপরিবর্তে ব্যবহারে উল্লেখযোগ্যভাবে উপকৃত হবে reduce

সুতরাং, applyসন্দেহ হলে আমি ব্যবহার করব ; এবং যদি আপনি জানতে পারেন যে এটি আপনাকে কোনও কিছু কিনছে না reduce(এবং এটি খুব শীঘ্রই পরিবর্তিত হওয়ার সম্ভাবনা নেই), reduceআপনি যদি মনে করেন তবে এই ক্ষুদ্র অপ্রয়োজনীয় ওভারহেড শেভ করার জন্য নির্দ্বিধায় ব্যবহার করুন


দুর্দান্ত উত্তর। সাইড নোটে, কেন sumহেস্কেলের মতো বিল্ট-ইন ফাংশন অন্তর্ভুক্ত করবেন না ? দেখতে বেশ সাধারণ একটি অপারেশন বলে মনে হচ্ছে।
dbyrne

17
ধন্যবাদ, শুনে খুশি! পুনরায় sum:, আমি বলব ক্লোজারের এই ফাংশন রয়েছে, এটি বলা হয় +এবং আপনি এটি দিয়ে এটি ব্যবহার করতে পারেন apply। :-) সিরিয়াসলি বললে, আমি লিস্পে মনে করি, সাধারণভাবে, যদি কোনও বৈকল্পিক ফাংশন সরবরাহ করা হয় তবে এটি সাধারণত সংগ্রহের উপর পরিচালিত একটি মোড়কের সাহায্যে হয় না - এটিই আপনি ব্যবহার applyকরেন (বা reduceআপনি যদি জানেন যে এটি আরও অর্থবোধ করে)।
মাইচা মার্কজিক

6
মজার, আমার পরামর্শটি এর বিপরীত: reduceযখন সন্দেহ হয়, applyযখন আপনি নিশ্চিতভাবে জানবেন একটি অপ্টিমাইজেশন রয়েছে। reduceএর চুক্তিটি আরও সুনির্দিষ্ট এবং এর ফলে সাধারণ অপ্টিমাইজেশনের প্রবণতা বেশি। applyআরও অস্পষ্ট এবং সুতরাং কেবলমাত্র কেস-কেস-কেস ভিত্তিতে অনুকূলিত করা যায়। strএবং concatদুটি প্রচলিত ব্যতীত।
সিগ্র্যান্ড

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


21

মতামতগুলি পৃথক হয় - বৃহত্তর লিস্প বিশ্বে reduceঅবশ্যই অবশ্যই আরও মূর্খবাদী বলে বিবেচিত হয়। প্রথমত, ইতিমধ্যে আলোচিত বৈচিত্রপূর্ণ সমস্যা রয়েছে। এছাড়াও, কিছু সাধারণ লিস্প সংকলক যখন applyখুব দীর্ঘ তালিকার বিরুদ্ধে প্রয়োগ করা হয় তখন তারা ব্যর্থ হবে কারণ তারা কীভাবে যুক্তি তালিকাগুলি পরিচালনা করে।

আমার চেনাশোনাতে ক্লোজুরিস্টদের মধ্যে যদিও applyএই ক্ষেত্রে ব্যবহার করা আরও সাধারণ বলে মনে হয়। আমি এটাকে পছন্দ করা পছন্দ করি এবং পছন্দ করি।


19

এটি এই ক্ষেত্রে কোনও পার্থক্য রাখে না, কারণ + একটি বিশেষ মামলা যা কোনও কোনও যুক্তি প্রয়োগ করতে পারে। হ্রাস একটি ফাংশন প্রয়োগ করার একটি উপায় যা আর্গুমেন্টের নির্বিচারে দীর্ঘ তালিকায় একটি নির্দিষ্ট সংখ্যক আর্গুমেন্ট (2) আশা করে।


9

আমি সাধারণত যে কোনও ধরণের সংগ্রহে অভিনয় করার সময় নিজেকে হ্রাস করতে পছন্দ করি - এটি ভাল সম্পাদন করে এবং সাধারণভাবে এটি বেশ কার্যকর কার্যকরী কাজ।

আমি প্রয়োগটি ব্যবহার করার মূল কারণটি হ'ল প্যারামিটারগুলির অর্থ বিভিন্ন পজিশনে বিভিন্ন জিনিস, বা আপনার কাছে প্রাথমিক প্যারামিটার দুটি থাকলেও সংগ্রহ থেকে বাকীটি পেতে চান, যেমন

(apply + 1 2 other-number-list)

9

এই নির্দিষ্ট ক্ষেত্রে আমি পছন্দ করি reduceকারণ এটি আরও পাঠযোগ্য : যখন আমি পড়ি

(reduce + some-numbers)

আমি অবিলম্বে জানি যে আপনি একটি ক্রমকে একটি মানতে পরিণত করছেন turning

সঙ্গে applyআমি বিবেচনা যা ফাংশন প্রয়োগ করা হচ্ছে আছে: "আহ, এটা +ফাংশন, তাই আমি পেয়ে করছি ... একটি একক সংখ্যা"। সামান্য কম সোজা।


7

+ এর মতো কোনও সাধারণ ক্রিয়াকলাপটি ব্যবহার করার সময়, আপনি কোনটি ব্যবহার করেন তা সত্যিই গুরুত্বপূর্ণ নয়।

সাধারণভাবে, ধারণাটি হ'ল এটি reduceএকটি জমে থাকা অপারেশন। আপনি আপনার সঞ্চিত ফাংশনে বর্তমান জমে থাকা মান এবং একটি নতুন মান উপস্থাপন করেন ফাংশনটির ফলাফলটি পরবর্তী পুনরাবৃত্তির জন্য সম্মিলিত মান। সুতরাং, আপনার পুনরাবৃত্তিগুলি দেখতে দেখতে:

cum-val[i+1] = F( cum-val[i], input-val[i] )    ; please forgive the java-like syntax!

প্রয়োগের জন্য, ধারণাটি হ'ল আপনি বেশ কয়েকটি স্কেলার আর্গুমেন্টের প্রত্যাশা করে একটি ফাংশন কল করার চেষ্টা করছেন, তবে সেগুলি বর্তমানে সংগ্রহে রয়েছে এবং এগুলি টেনে আনা দরকার। সুতরাং, পরিবর্তে বলার অপেক্ষা রাখে:

vals = [ val1 val2 val3 ]
(some-fn (vals 0) (vals 1) (vals 2))

আমরা বলতে পারেন:

(apply some-fn vals)

এবং এটি এর সমতুল্য রূপান্তরিত হয়:

(some-fn val1 val2 val3)

সুতরাং, "প্রয়োগ" ব্যবহারটি ক্রমের চারপাশে "প্রথম বন্ধনীর অপসারণ" এর মতো।


4

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

user=> (time (reduce + (range 1e3)))
"Elapsed time: 5.543 msecs"
499500
user=> (time (apply + (range 1e3))) 
"Elapsed time: 5.263 msecs"
499500
user=> (time (apply + (range 1e4)))
"Elapsed time: 19.721 msecs"
49995000
user=> (time (reduce + (range 1e4)))
"Elapsed time: 1.409 msecs"
49995000
user=> (time (reduce + (range 1e5)))
"Elapsed time: 17.524 msecs"
4999950000
user=> (time (apply + (range 1e5)))
"Elapsed time: 11.548 msecs"
4999950000

ক্লোজারের সোর্স কোডটি দেখে অভ্যন্তরীণ-হ্রাসের সাথে এর সুন্দর পরিচ্ছন্ন পুনরাবৃত্তি হ্রাস করা হয়েছে, যদিও প্রয়োগের প্রয়োগের ক্ষেত্রে কিছু পাওয়া যায় নি। অভ্যন্তরীণভাবে অনুরোধ কমানোর জন্য + প্রয়োগের ক্লোজার বাস্তবায়ন হ'ল রেপ দ্বারা ক্যাশে করা হয়েছে, যা 4 র্থ কল ব্যাখ্যা করে বলে মনে হচ্ছে। এখানে কেউ কী ঘটছে তা স্পষ্ট করে বলতে পারে?


আমি জানি আমি যখনই পারি কমাতে পছন্দ করব :)
রোহিত

2
আপনার rangeকলটি timeফর্মের ভিতরে রাখা উচিত নয় । সিক্যুয়েন্স নির্মাণের হস্তক্ষেপ সরানোর জন্য এটি বাইরে রাখুন। আমার ক্ষেত্রে, reduceধারাবাহিকভাবে ছাপিয়ে যায় apply
ডেভিঝু

3

প্রয়োগের সৌন্দর্যে ফাংশন দেওয়া হয় (+ এই ক্ষেত্রে) একটি সমাপ্ত সংগ্রহ সহ প্রাক-মুলতুবি হস্তক্ষেপ যুক্তি দ্বারা গঠিত আর্গুমেন্ট তালিকায় প্রয়োগ করা যেতে পারে। হ্রাস হ'ল প্রতিটি জন্য ফাংশন প্রয়োগ করে সংগ্রহ আইটেমগুলি প্রক্রিয়া করার জন্য বিমূর্ততা এবং ভেরিয়েবল আরগস ক্ষেত্রে কাজ করে না।

(apply + 1 2 3 [3 4])
=> 13
(reduce + 1 2 3 [3 4])
ArityException Wrong number of args (5) passed to: core/reduce  clojure.lang.AFn.throwArity (AFn.java:429)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.