ফোল্ডার বনাম ভাঁজ (বা ফোল্ড ') এর প্রভাব


155

প্রথমত, রিয়েল ওয়ার্ল্ড হাস্কেল , যা আমি পড়ছি, কখনও ব্যবহার foldlএবং পরিবর্তে ব্যবহার করার কথা বলে foldl'। সুতরাং আমি এটি বিশ্বাস।

তবে কখন আমি foldrভার্সেস ব্যবহার করব তা নিয়ে আমি বিরক্ত foldl'। যদিও তারা আমার সামনে কীভাবে আলাদাভাবে কাজ করে তার কাঠামোটি দেখতে পাচ্ছি, তবে "কখন ভাল" তা বুঝতে আমি খুব বোকা। আমি অনুমান করি এটি আমার কাছে মনে হয় যা সত্যই ব্যবহৃত হয় যা ব্যবহার করা উচিত নয়, কারণ তারা উভয়ই একই উত্তর দেয় (তারা না?) প্রকৃতপক্ষে, এই নির্মাণের সাথে আমার পূর্ববর্তী অভিজ্ঞতাটি রুবি injectএবং ক্লোজারের reduce, যা "বাম" এবং "ডান" সংস্করণ বলে মনে হয় না। (পার্শ্ব প্রশ্ন: তারা কোন সংস্করণ ব্যবহার করে?)

আমার মতো স্মার্ট-চ্যালেঞ্জযুক্ত বাছাই করতে সহায়তা করতে পারে এমন কোনও অন্তর্দৃষ্টি প্রশংসা পাবে!

উত্তর:


174

foldr f x ysযেখানে ys = [y1,y2,...,yk]দেখতে দেখতে পুনরাবৃত্তি

f y1 (f y2 (... (f yk x) ...))

যদিও foldl f x ysচেহারা জন্য পুনরাবৃত্তি

f (... (f (f x y1) y2) ...) yk

এখানে একটি গুরুত্বপূর্ণ পার্থক্য হ'ল যদি ফলাফলটি f x yকেবলমাত্র এর মান ব্যবহার করে গণনা করা যায় x, তবে foldr'পুরো তালিকাটি পরীক্ষা করার দরকার নেই। উদাহরণ স্বরূপ

foldr (&&) False (repeat False)

Falseযেখানে ফিরে

foldl (&&) False (repeat False)

কখনই শেষ হয় না। (দ্রষ্টব্য: repeat Falseপ্রতিটি উপাদান যেখানে রয়েছে একটি অসীম তালিকা তৈরি করে False))

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


2
ফোল্ডারে এটি f y1 থাঙ্ক হিসাবে মূল্যায়ন করে, তাই এটি মিথ্যা প্রত্যাবর্তন করে, তবে ভাঁজগুলিতে, f এটির প্যারামিটারের কোনওটিই জানতে পারে না ll খুব বড়. ভাঁজ 'কার্যকরভাবে বরাবর thunk হ্রাস করতে পারে।
সাওয়ের

25
বিভ্রান্তি এড়াতে, নোট করুন যে প্রথম বন্ধনী মূল্যায়নের প্রকৃত অর্ডারটি প্রদর্শন করে না। যেহেতু হাস্কেল অলস, বহিরাগততম প্রকাশগুলি প্রথমে মূল্যায়ন করা হবে।
Lii

গ্রেট উত্তর। আমি যুক্ত করতে চাই যে আপনি যদি এমন একটি ভাঁজ চান যা কোনও তালিকার মাধ্যমে পার্ট ওয়ে থামতে পারে তবে আপনার ফোল্ডারটি ব্যবহার করতে হবে; আমার ভুল না হলে বাম ভাঁজগুলি থামানো যায় না। (আপনি যদি বলেন "আপনি যদি জানেন ... আপনি ... পুরো তালিকাটি অতিক্রম করবেন" তখন আপনি এটি ইঙ্গিত করেছেন)। এছাড়াও, "কেবলমাত্র মানটি ব্যবহার করে" টাইপওকে "কেবলমাত্র মানটি ব্যবহার করে" এ পরিবর্তন করা উচিত। অর্থাৎ "চালু" শব্দটি সরিয়ে দিন। (স্ট্যাকওভারফ্লো আমাকে 2 চরের পরিবর্তন জমা দিতে দেয় না!)।
Lqueryvg

বাম ভাঁজগুলি বন্ধ করার জন্য লিক্যুরিভগকে দুটি উপায়: ১. ডান ভাঁজ দিয়ে এটি কোড করুন (দেখুন fodlWhile); ২ scanl) এটিকে একটি বাম স্ক্যানে রূপান্তর করুন ( ) এবং এর সাথে last . takeWhile pবা অনুরূপটি থামান । উহ, এবং 3. ব্যবহার mapAccumL। :)
নেস

1
@ দেস্টি কারণ এটি প্রতিটি পদক্ষেপে তার সামগ্রিক ফলাফলের নতুন অংশ উত্পাদন করে - এর বিপরীতে foldl, যা তার সামগ্রিক ফলাফল সংগ্রহ করে এবং সমস্ত কাজ শেষ হওয়ার পরেই এটিকে উত্পাদন করে এবং আরও কার্যকর করার কোনও পদক্ষেপ নেই। সুতরাং উদাহরণস্বরূপ foldl (flip (:)) [] [1..3] == [3,2,1], তাই scanl (flip(:)) [] [1..] = [[],[1],[2,1],[3,2,1],...]... আইওডাব্লু, foldl f z xs = last (scanl f z xs)এবং অসীম তালিকার কোনও শেষ উপাদান নেই (যা উপরের উদাহরণে, নিজেই আইএনএফ থেকে নীচে 1 পর্যন্ত একটি অসীম তালিকা হবে)।
নেস


33

তাদের শব্দার্থবিজ্ঞানের পার্থক্য তাই আপনি কেবল আদান প্রদান করতে পারবেন না foldlএবং foldr। একটি উপাদান বাম থেকে উপরে ভাঁজ করে, অন্যটি ডান দিক থেকে ভাঁজ করে। এইভাবে, অপারেটরটি একটি পৃথক ক্রমে প্রয়োগ হয়। বিয়োগের মতো সমস্ত অ-সাহসী ক্রিয়াকলাপের জন্য এটি গুরুত্বপূর্ণ।

হাস্কেল.অর্গ.বিষয়টির একটি আকর্ষণীয় নিবন্ধ রয়েছে।


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

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


18

সমস্ত ব্যবহারের 99% এর কারণটির foldl'পক্ষে পছন্দনীয় কারণ এটি foldlবেশিরভাগ ব্যবহারের জন্য ধ্রুব স্থানে চলতে পারে।

ফাংশন নিন sum = foldl['] (+) 0। যখন foldl'ব্যবহৃত হয়, যোগফলটি তত্ক্ষণাত গণনা করা হয়, সুতরাং sumঅসীম তালিকায় প্রয়োগ করা কেবল চিরকালের জন্য চলবে, এবং সম্ভবত ধ্রুবক স্থানে (যদি আপনি Ints, Doubles, Floats এর মতো জিনিস Integerব্যবহার করেন তবে ধ্রুবক স্থানের চেয়ে বেশি ব্যবহার করবেন যদি সংখ্যাটি বড় হয়ে যায় maxBound :: Int)।

এর সাথে foldl, একটি থঙ্ক তৈরি করা হয়েছে (উত্তর কীভাবে পাওয়া যায় তার একটি রেসিপির মতো, যা উত্তর সংরক্ষণের পরিবর্তে পরে মূল্যায়ন করা যায়)। এই থঙ্কগুলি প্রচুর জায়গা নিতে পারে, এবং এই ক্ষেত্রে, থাঙ্কটি সংরক্ষণ করার চেয়ে ভাবটি মূল্যায়ন করা ভাল (একটি স্ট্যাকের ওভারফ্লোতে পরিচালিত… এবং আপনাকে নেতৃত্ব দেবে ... ওহে কিছু মনে করবেন না)

আশা করি এইটি কাজ করবে.


1
বড় ব্যতিক্রমটি হ'ল যদি ফাংশনটি foldlতার এক বা একাধিক আর্গুমেন্টে কন্সট্রাক্টর প্রয়োগ ছাড়া কিছুই না করে।
dfeuer

foldlআসলে কখন সেরা পছন্দটি রয়েছে তার কোনও সাধারণ প্যাটার্ন রয়েছে ? (অসীম তালিকার মতো কখন foldrভুল পছন্দ, অপ্টিমাইজেশন বুদ্ধিমান??)
Evi1M4chine

@ Evi1M4chine foldrঅসীম তালিকার ভুল পছন্দ হয়ে আপনি কী বোঝাতে চাইছেন তা নিশ্চিত হন না । আসলে, আপনার ব্যবহার করা উচিত নয় foldlবা foldl'অসীম তালিকার জন্য। স্ট্যাক ওভারফ্লোতে হাস্কেল উইকি
কেভিনআর

14

উপায় দ্বারা, রুবি এর injectএবং Clojure এর reduceদ্বারা foldl(অথবা foldl1, কোন সংস্করণটি আপনি ব্যবহার উপর নির্ভর করে)। সাধারণত, যখন কোনও ভাষায় কেবল একটি ফর্ম থাকে, তখন পাইথন reduce, পার্ল List::Util::reduce, সি ++ এর accumulate, সি # এর Aggregate, ছোট্টকল inject:into:, পিএইচপি array_reduce, ম্যাথমেটিকাসহ একটি বাম ভাঁজ থাকে বাম ভাঁজে Foldসাধারণ লিস্পের reduceডিফল্ট তবে ডান ভাঁজের জন্য বিকল্প রয়েছে।


2
এই মন্তব্য সহায়ক তবে আমি উত্স প্রশংসা করব।
টাইটানিয়ামডেকয়

সাধারণ লিস্পটি reduceঅলস নয়, সুতরাং এটি foldl'এবং এখানে বিবেচনাগুলির বেশিরভাগটি প্রয়োগ হয় না।
মাইক্রো ভাইরাস

আমার মনে হয় আপনার অর্থ foldl', এগুলি যেমন কঠোর ভাষা, না? অন্যথায়, এর অর্থ এই নয় যে সমস্ত সংস্করণগুলি স্ট্যাকের ওভারফ্লোগুলি এর মতো foldlকরে?
Evi1M4chine

6

কনরাড যেমন উল্লেখ করেছেন, তাদের শব্দার্থবিজ্ঞান আলাদা। এমনকি তাদের একই ধরণের নেই:

ghci> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
ghci> :t foldl
foldl :: (a -> b -> a) -> a -> [b] -> a
ghci> 

উদাহরণস্বরূপ, তালিকা সংযোজন অপারেটর (++) foldrহিসাবে প্রয়োগ করা যেতে পারে

(++) = flip (foldr (:))

যখন

(++) = flip (foldl (:))

আপনাকে একটি ধরণের ত্রুটি দেবে।


তাদের ধরণ একই, কেবল চারদিকে স্যুইচ করা, যা অপ্রাসঙ্গিক। তাদের ইন্টারফেস এবং ফলাফল একই, বাজে পি / এনপি সমস্যা বাদে (পড়ুন: অসীম তালিকাগুলি)। ;) বাস্তবায়নের কারণে অপ্টিমাইজেশানটি বাস্তবে কেবলমাত্র পার্থক্য, যতদূর আমি বলতে পারি।
Evi1M4chine

@ Evi1M4chine এটি ভুল, এই উদাহরণটি দেখুন: foldl subtract 0 [1, 2, 3, 4] মূল্যায়ন করার -10সময়, foldr subtract 0 [1, 2, 3, 4]মূল্যায়ন করার সময় -2foldlআসলে 0 - 1 - 2 - 3 - 4যখন foldrহয় 4 - 3 - 2 - 1 - 0
ক্র্যাফ্ট

@ ক্র্যাফ্ট, foldr (-) 0 [1, 2, 3, 4]হ'ল -2এবং foldl (-) 0 [1, 2, 3, 4]হ'ল -10। অন্যদিকে, subtractআপনি যা প্রত্যাশা করতে পারেন তার থেকে পিছনে রয়েছে ( subtract 10 14যেমন 4), তেমনি foldr subtract 0 [1, 2, 3, 4]হয় -10এবং foldl subtract 0 [1, 2, 3, 4]হয় 2(ধনাত্মক)।
পিয়ানোজেমস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.