ভাঁজ বনাম ফোল্ডার আচরণ অসীম তালিকার সাথে


124

এই প্রশ্নের মায়া ফাংশনের কোডটি ফোল্ডার ব্যবহার করে। শিকারী সন্তুষ্ট হলে এটি একটি অসীম তালিকার প্রক্রিয়াকরণ বন্ধ করে দেয়।

আমি ভাঁজ ব্যবহার করে এটি আবার লিখেছি:

myAny :: (a -> Bool) -> [a] -> Bool
myAny p list = foldl step False list
   where
      step acc item = p item || acc

(নোট করুন যে পদক্ষেপের কার্যক্রমে যুক্তিগুলি সঠিকভাবে বিপরীত হয়েছে))

তবে এটি আর অসীম তালিকাগুলি প্রক্রিয়াকরণ বন্ধ করে দেয়।

আমি অ্যাপোক্যালিস্পের উত্তরের মতো ফাংশনটির কার্যকরকরণটি সনাক্ত করার চেষ্টা করেছি :

myAny even [1..]
foldl step False [1..]
step (foldl step False [2..]) 1
even 1 || (foldl step False [2..])
False  || (foldl step False [2..])
foldl step False [2..]
step (foldl step False [3..]) 2
even 2 || (foldl step False [3..])
True   || (foldl step False [3..])
True

যাইহোক, এটি ফাংশনটি আচরণ করে না। এটা কীভাবে ভুল?

উত্তর:


231

foldএর পার্থক্য কীভাবে বিভ্রান্তির ঘন ঘন উত্স বলে মনে হয়, তাই এখানে আরও সাধারণ সংক্ষিপ্ত বিবরণ দেওয়া হল:

[x1, x2, x3, x4 ... xn ]কিছু ফাংশন fএবং বীজের সাথে এন মানগুলির একটি তালিকা ভাঁজ করা বিবেচনা করুন z

foldl হল:

  • বাম সংঘবদ্ধ :f ( ... (f (f (f (f z x1) x2) x3) x4) ...) xn
  • লেজ পুনরাবৃত্তি : এটি তালিকার মাধ্যমে পুনরাবৃত্তি করে পরে মানটি তৈরি করে
  • অলস : ফলাফল প্রয়োজন না হওয়া পর্যন্ত কিছুই মূল্যায়ন করা হয় না
  • পিছনে : foldl (flip (:)) []একটি তালিকা বিপরীত।

foldr হল:

  • ডান সহযোগী :f x1 (f x2 (f x3 (f x4 ... (f xn z) ... )))
  • একটি যুক্তিতে পুনরাবৃত্তি: প্রতিটি পুনরাবৃত্তি fপরবর্তী মান এবং তালিকার বাকী ভাঁজ ফলাফলের জন্য প্রযোজ্য ।
  • অলস : ফলাফল প্রয়োজন না হওয়া পর্যন্ত কিছুই মূল্যায়ন করা হয় না
  • ফরোয়ার্ড : foldr (:) []অপরিবর্তিত তালিকা ফিরিয়ে দেয়।

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

এটি স্পষ্টতই কার্যকর লেজ-পুনরাবৃত্তি থেকে সর্বাধিক কার্যনির্বাহী প্রোগ্রামাররা জানেন এবং ভালোবাসেন cry

প্রকৃতপক্ষে, যদিও foldlপ্রযুক্তিগতভাবে পুচ্ছ-পুনরাবৃত্ত হয়, কারণ পুরো ফলাফল প্রকাশটি কোনও কিছুর মূল্যায়ন করার আগেই নির্মিত হয়েছিল, foldlস্ট্যাকের ওভারফ্লো হতে পারে!

অন্যদিকে, বিবেচনা করুন foldr। এটিও অলস, তবে এটি এগিয়েf চলেছে বলে প্রতিটি প্রয়োগ ফলাফলের অভ্যন্তরে যুক্ত করা হয় । সুতরাং, ফলাফলটি গণনা করতে, হাস্কেল একটি একক ফাংশন অ্যাপ্লিকেশন তৈরি করে, যার দ্বিতীয় যুক্তিটি ভাঁজ তালিকার বাকি অংশ। যদি fএকটি ডাটা কন্সট্রাকটর, উদাহরণস্বরূপ - - তার দ্বিতীয় যুক্তি অলস ফল কী হবে বৃদ্ধিলাভ অলস এর নির্ণিত ভাঁজ প্রতিটি পদক্ষেপ সঙ্গে, শুধুমাত্র যখন ফলে চাহিদা এটা মূল্যায়ন করা হয় কিছু অংশ।

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

সুতরাং দুটি গুরুত্বপূর্ণ বিষয় লক্ষণীয়:

  • foldr একটি অলস পুনরাবৃত্ত তথ্য কাঠামো অন্যটিতে রূপান্তর করতে পারে।
  • অন্যথায়, অলস ভাঁজগুলি বৃহত বা অসীম তালিকায় স্ট্যাকের ওভারফ্লো দিয়ে ক্রাশ হবে।

আপনি লক্ষ্য করেছেন যে দেখে মনে হচ্ছে এটি foldrসবকিছু foldlকরতে পারে আরও কিছু করতে পারে। এটা সত্য! আসলে, ভাঁজ প্রায় বেহুদা!

তবে যদি আমরা কোনও বৃহত (তবে অসীম নয়) তালিকায় ভাঁজ করে একটি অলস ফলাফল তৈরি করতে চাই তবে কী হবে? এর জন্য, আমরা একটি কঠোর ভাঁজ চাই , যা মানক গ্রন্থাগারগুলি যদিও সাফল্যের সাথে সরবরাহ করে :

foldl' হল:

  • বাম সংঘবদ্ধ :f ( ... (f (f (f (f z x1) x2) x3) x4) ...) xn
  • লেজ পুনরাবৃত্তি : এটি তালিকার মাধ্যমে পুনরাবৃত্তি করে পরে মানটি তৈরি করে
  • কঠোর : প্রতিটি ফাংশন অ্যাপ্লিকেশনটি পাশাপাশি মূল্যায়ন করা হয়
  • পিছনে : foldl' (flip (:)) []একটি তালিকা বিপরীত।

কারণ foldl'হল কঠোর , গনা ফলাফলের জন্য Haskell হবে মূল্যায়নের f পরিবর্তে বাম যুক্তি লেট প্রতিটি পদক্ষেপ, একটি বিশাল, unevaluated অভিব্যক্তি বাড়তে থাকে। এটি আমাদের স্বাভাবিক, কার্যকর লেজ পুনরাবৃত্তি দেয়! অন্য কথায়:

  • foldl' দক্ষতার সাথে বড় তালিকা ভাঁজ করতে পারেন।
  • foldl' অসীম তালিকায় একটি অসীম লুপে ঝুলবে (স্ট্যাকের উপচে পড়বে না)।

হাস্কেল উইকির একটি পৃষ্ঠাও এটি নিয়ে আলোচনা করেছে ।


6
আমি এখানে আসার কারণ আমি জানতে আগ্রহী নই কেন foldrভাল চেয়ে foldlমধ্যে Haskell, যখন বিপরীত সত্য Erlang (যা আমি আগে শিখেছি Haskell, )। যেহেতু Erlang অলস নয় এবং ফাংশন নেই curried , তাই foldlমধ্যে Erlang মত আচরণ foldl'উপরে। এটি একটি দুর্দান্ত উত্তর! ভাল কাজ এবং ধন্যবাদ!
সিউ চিং পং-আসুকা কেনজি-

7
এটি বেশিরভাগ ক্ষেত্রে দুর্দান্ত ব্যাখ্যা, তবে আমি foldl"পশ্চাদপদ" এবং foldr"ফরোয়ার্ড" হিসাবে সমস্যাযুক্ত হিসাবে বর্ণনা পাই । এটি অংশে রয়েছে কারণ কেন ভাঁজ পিছনে রয়েছে এর দৃষ্টান্তটিতে flipপ্রয়োগ করা হচ্ছে (:)। প্রাকৃতিক প্রতিক্রিয়াটি হ'ল, "অবশ্যই এটি পিছিয়ে: আপনি flipপেডের তালিকার উপসংহার!" এটি "অবাক" হিসাবে দেখতে পারা অবাক করা কারণ সম্পূর্ণ মূল্যায়নের foldlক্ষেত্রে fপ্রথম তালিকার উপাদানটি প্রথমে (অন্তর্নিহিত) প্রযোজ্য । এটি প্রথমে শেষ উপাদানটিতে foldrপ্রয়োগ fকরে "পিছিয়ে যায়" ।
ডেভ আব্রাহামস

1
@DaveAbrahams: মধ্যে মাত্র foldlএবং foldrএবং কষাকষি এবং অপ্টিমাইজেশন, প্রথম মানে হলো "দূরতম" উপেক্ষা না "অন্তরতম"। এই কারণেই foldrঅসীম তালিকাগুলি প্রক্রিয়া করতে পারে এবং পারে foldlনা - ডান ভাঁজটি প্রথমে fপ্রথম তালিকার উপাদান এবং লেজ ভাঁজ করার (মূল্যহীন) ফলাফলের জন্য প্রযোজ্য , যখন বাম ভাঁজটির বহিরাগত প্রয়োগের মূল্যায়ন করতে পুরো তালিকাটি অতিক্রম করতে হবে f
সিএ ম্যাকক্যান

1
আমি কেবল ভাবছি যে এখানে কোনও উদাহরণ রয়েছে যেখানে ভাঁজটির চেয়ে ভাঁজটিকেই প্রাধান্য দেওয়া হবে ', আপনি কি মনে করেন একটি আছে?
কাজুউয়া

1
@ kazuoua যেখানে অলসতা প্রয়োজনীয়, যেমন last xs = foldl (\a z-> z) undefined xs
নেস

28
myAny even [1..]
foldl step False [1..]
foldl step (step False 1) [2..]
foldl step (step (step False 1) 2) [3..]
foldl step (step (step (step False 1) 2) 3) [4..]

প্রভৃতি

স্বজ্ঞাতভাবে, foldlসর্বদা "বাহিরে" বা "বামে" থাকে তাই এটি প্রথমে প্রসারিত হয়। সীমাহীনভাবে.


10

আপনি এখানে হাস্কেলের ডকুমেন্টেশনে দেখতে পাচ্ছেন যে ভাঁজটি লেজ-পুনরাবৃত্তিযোগ্য এবং অসীম তালিকা পাস হলে কখনও শেষ হবে না, কারণ এটি কোনও মান ফেরানোর আগে পরবর্তী প্যারামিটারে নিজেকে কল করে ...


0

আমি হাস্কেলকে চিনি না, তবে স্কিমে fold-rightসর্বদা প্রথমে একটি তালিকার শেষ উপাদানটির উপর 'অভিনয়' করবে। এটি চক্রীয় তালিকার জন্য কাজ করবে না (যা অসীম হিসাবে একই)।

আমি নিশ্চিত না যে fold-rightলেজ-পুনরাবৃত্তি লেখা যায় কিনা , তবে যে কোনও চক্রের তালিকার জন্য আপনার স্ট্যাকের ওভারফ্লো হওয়া উচিত। fold-leftOTOH সাধারণত লেজ পুনরাবৃত্তির সাথে প্রয়োগ করা হয়, এবং তা যদি তাড়াতাড়ি বন্ধ না করে তবে কেবল একটি অসীম লুপে আটকে যাবে।


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