আমি টেল-কল অপ্টিমাইজেশন (লেজ-পুনরাবৃত্তি এবং ধারাবাহিকতা-পাসিং শৈলী উভয় পরিচালনা করে) সম্পাদনা করে একটি মডিউল প্রকাশ করেছি: https://github.com/baruchel/tco
পাইথনে লেজ-পুনরাবৃত্তির অনুকূলকরণ
প্রায়শই দাবি করা হয়েছে যে লেজ-পুনরাবৃত্তি কোডিংয়ের পাইথোনিক পদ্ধতির সাথে খাপ খায় না এবং এটি কীভাবে একটি লুপে এম্বেড করা যায় সে সম্পর্কে কোনও চিন্তা করা উচিত নয়। আমি এই দৃষ্টিকোণ দিয়ে তর্ক করতে চাই না; কখনও কখনও তবে আমি বিভিন্ন কারণে লুপগুলি না দিয়ে টেল-রিকার্স ফাংশন হিসাবে নতুন ধারণাগুলি চেষ্টা বা প্রয়োগ করতে পছন্দ করি (প্রক্রিয়াটির চেয়ে ধারণাটির দিকে মনোনিবেশ করা, একই সাথে আমার পর্দায় বিশটি সংক্ষিপ্ত ফাংশন একই সাথে কেবল তিনটি "পাইথোনিক" ফাংশন, আমার কোড সম্পাদনা করার পরিবর্তে একটি ইন্টারেক্টিভ সেশনে কাজ করা ইত্যাদি)।
পাইথনে লেজ-পুনরাবৃত্তির অপ্টিমাইজ করা আসলে বেশ সহজ। যদিও এটি অসম্ভব বা খুব কৃপণ বলে মনে হচ্ছে, আমি মনে করি এটি মার্জিত, সংক্ষিপ্ত এবং সাধারণ সমাধান দিয়ে অর্জন করা যেতে পারে; আমি এমনকি মনে করি যে এই সমাধানগুলির বেশিরভাগটি পাইথন বৈশিষ্ট্যগুলি ব্যবহার করা উচিত নয় otherwise খুব স্ট্যান্ডার্ড লুপের সাথে পরিচ্ছন্ন ল্যাম্বদা এক্সপ্রেশনগুলি লেজ-পুনরাবৃত্তি অপ্টিমাইজেশান বাস্তবায়নের জন্য দ্রুত, দক্ষ এবং সম্পূর্ণরূপে ব্যবহারযোগ্য সরঞ্জামের দিকে পরিচালিত করে।
একটি ব্যক্তিগত সুবিধার্থে, আমি দুটি ভিন্ন উপায়ে যেমন একটি অপ্টিমাইজেশন প্রয়োগ করে একটি ছোট মডিউল লিখেছিলাম। আমি আমার দুটি প্রধান কার্যাদি সম্পর্কে এখানে আলোচনা করতে চাই।
পরিষ্কার উপায়: ওয়াই সংযুক্তকারীকে সংশোধন করা
ওয়াই combinator সুপরিচিত হয়; এটি একটি পুনরাবৃত্ত পদ্ধতিতে ল্যাম্বদা ফাংশনগুলি ব্যবহার করতে দেয় তবে এটি নিজেই কোনও লুপে পুনরাবৃত্ত কলগুলি এম্বেড করার অনুমতি দেয় না। ল্যাম্বদা ক্যালকুলাস একাই এ জাতীয় কাজ করতে পারে না। ওয়াই কম্বিনেটরে সামান্য পরিবর্তন তবে প্রকৃত মূল্যায়নের জন্য পুনরাবৃত্ত কলকে সুরক্ষা দিতে পারে। মূল্যায়ন এইভাবে বিলম্ব হতে পারে।
ওয়াই সংযুক্তকারীটির জন্য এখানে বিখ্যাত অভিব্যক্তিটি রয়েছে:
lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
খুব সামান্য পরিবর্তন সহ, আমি পেতে পারি:
lambda f: (lambda x: x(x))(lambda y: f(lambda *args: lambda: y(y)(*args)))
নিজেকে কল করার পরিবর্তে, ফাংশনটি এখন একই कॉल সম্পাদন করে একটি ফাংশন ফিরিয়ে দেয়, তবে যেহেতু এটি এটি ফেরত দেয়, পরে মূল্যায়ন বাইরে থেকে করা যায়।
আমার কোডটি হ'ল:
def bet(func):
b = (lambda f: (lambda x: x(x))(lambda y:
f(lambda *args: lambda: y(y)(*args))))(func)
def wrapper(*args):
out = b(*args)
while callable(out):
out = out()
return out
return wrapper
ফাংশনটি নিম্নলিখিত উপায়ে ব্যবহার করা যেতে পারে; ফ্যাটোরিয়াল এবং ফিবোনাকির লেজ-পুনরাবৃত্ত সংস্করণের দুটি উদাহরণ এখানে রয়েছে:
>>> from recursion import *
>>> fac = bet( lambda f: lambda n, a: a if not n else f(n-1,a*n) )
>>> fac(5,1)
120
>>> fibo = bet( lambda f: lambda n,p,q: p if not n else f(n-1,q,p+q) )
>>> fibo(10,0,1)
55
স্পষ্টতই পুনরাবৃত্তি গভীরতা কোনও সমস্যা নয়:
>>> bet( lambda f: lambda n: 42 if not n else f(n-1) )(50000)
42
এটি অবশ্যই ফাংশনের একক আসল উদ্দেশ্য।
এই অপ্টিমাইজেশনের সাথে কেবল একটি জিনিস করা যায় না: এটি অন্য ফাংশনে মূল্যায়ন করে একটি লেজ-পুনরাবৃত্ত ফাংশন ব্যবহার করা যাবে না (এটি সত্য যে আসে যে কলযোগ্য ফেরত আসা বস্তুগুলি সমস্ত পার্থক্য ছাড়াই পুনরাবৃত্ত কল হিসাবে পরিচালিত হয়)। যেহেতু সাধারণত আমার এ জাতীয় বৈশিষ্ট্যের প্রয়োজন হয় না, তাই উপরের কোডটি নিয়ে আমি খুব খুশি। যাইহোক, আরও সাধারণ মডিউল সরবরাহ করার জন্য, আমি এই ইস্যুটির জন্য কিছুটা কার্যকর করার জন্য কিছুটা আরও ভেবেছি (পরের অংশটি দেখুন)।
এই প্রক্রিয়াটির গতি সম্পর্কে (যা তবে আসল সমস্যা নয়) এটি বেশ ভাল বলে মনে হয়; লেজ-পুনরাবৃত্তি ফাংশন এমনকি সহজ এক্সপ্রেশন ব্যবহার করে নিম্নলিখিত কোডের তুলনায় অনেক দ্রুত মূল্যায়ন করা হয়:
def bet1(func):
def wrapper(*args):
out = func(lambda *x: lambda: x)(*args)
while callable(out):
out = func(lambda *x: lambda: x)(*out())
return out
return wrapper
আমি মনে করি যে একটি এক্সপ্রেশন মূল্যায়ন, এমনকি জটিল, বেশ কয়েকটি সহজ অভিব্যক্তি মূল্যায়নের চেয়েও দ্রুততর, যা এই দ্বিতীয় সংস্করণের ক্ষেত্রে। আমি এই নতুন ফাংশনটি আমার মডিউলটিতে রাখি নি এবং "অফিসিয়াল" না করে এটি ব্যবহার করার মতো কোনও পরিস্থিতি আমি দেখতে পাই না।
ব্যতিক্রম সহ ধারাবাহিকতা পাস করার শৈলী
এখানে আরও সাধারণ ফাংশন রয়েছে; এটি অন্যান্য ফাংশনগুলি ফিরিয়ে নেওয়া সহ সমস্ত পুচ্ছ-পুনরাবৃত্ত ফাংশনগুলি পরিচালনা করতে সক্ষম। পুনরাবৃত্ত কলগুলি ব্যতিক্রমগুলির ব্যবহারের মাধ্যমে অন্যান্য রিটার্ন মানগুলি থেকে স্বীকৃত। এই সমাধানগুলি আগেরটির চেয়ে ধীর; প্রধান লুপটিতে "পতাকাগুলি" সনাক্ত করা হিসাবে কিছু বিশেষ মান ব্যবহার করে একটি দ্রুত কোড সম্ভবত রচনা করা যেতে পারে তবে আমি বিশেষ মান বা অভ্যন্তরীণ কীওয়ার্ডগুলি ব্যবহার করার ধারণা পছন্দ করি না। ব্যতিক্রমগুলি ব্যবহার করার কিছু মজার ব্যাখ্যা রয়েছে: পাইথন যদি লেজ-পুনরাবৃত্ত কলগুলি পছন্দ না করে, একটি লেজ পুনরাবৃত্তি কল আসে তখন একটি ব্যতিক্রম উত্থাপন করা উচিত এবং কিছু পরিষ্কার খুঁজে পেতে পাইথোনিক উপায়টি ব্যতিক্রমটি ধরা হবে be সমাধান, যা আসলে এখানে ঘটে ...
class _RecursiveCall(Exception):
def __init__(self, *args):
self.args = args
def _recursiveCallback(*args):
raise _RecursiveCall(*args)
def bet0(func):
def wrapper(*args):
while True:
try:
return func(_recursiveCallback)(*args)
except _RecursiveCall as e:
args = e.args
return wrapper
এখন সমস্ত ফাংশন ব্যবহার করা যেতে পারে। নিম্নলিখিত উদাহরণে, f(n)
এন এর যে কোনও ধনাত্মক মানের জন্য পরিচয় ফাংশনটিতে মূল্যায়ন করা হয়:
>>> f = bet0( lambda f: lambda n: (lambda x: x) if not n else f(n-1) )
>>> f(5)(42)
42
অবশ্যই, এটি যুক্তিযুক্ত হতে পারে যে ব্যতিক্রমগুলি ইচ্ছাকৃতভাবে দোভাষীকে পুনঃনির্দেশের জন্য ব্যবহার করার উদ্দেশ্যে নয় (এক ধরণের goto
বিবৃতি বা সম্ভবত বরং এক ধরণের ধারাবাহিকতা পাস করার শৈলী হিসাবে), যা আমাকে স্বীকার করতে হবে। তবে, আবারও আমি try
একক লাইনটি return
বিবৃতি হিসাবে ব্যবহার করার ধারণাটি মজাদার বলে মনে করি: আমরা কিছু (স্বাভাবিক আচরণ) ফিরিয়ে দেওয়ার চেষ্টা করি তবে পুনরাবৃত্তির কল (ব্যতিক্রম) হওয়ার কারণে আমরা তা করতে পারি না।
প্রাথমিক উত্তর (2013-08-29)।
লেজ পুনরাবৃত্তি পরিচালনা করার জন্য আমি একটি খুব ছোট প্লাগইন লিখেছি। আপনি এখানে আমার ব্যাখ্যা সহ এটি পেতে পারেন: https://groups.google.com/forum/?hl=fr#!topic/comp.lang.python/dIsnJ2BoBKs
এটি অন্য ফাংশনে লেজ পুনরাবৃত্ত শৈলীর সাথে লিখিত একটি ল্যাম্বডা ফাংশন এম্বেড করতে পারে যা এটি লুপ হিসাবে মূল্যায়ন করবে।
এই ছোট ফাংশনের সবচেয়ে আকর্ষণীয় বৈশিষ্ট্যটি, আমার বিনীত মতে এটি হ'ল ফাংশনটি কিছু নোংরা প্রোগ্রামিং হ্যাকের উপর নির্ভর করে না তবে কেবল ল্যাম্বডা ক্যালকুলাসের উপর নির্ভর করে: অন্য ল্যাম্বডা ফাংশনে whenোকানো হলে ফাংশনের আচরণটি অন্যটিতে পরিবর্তিত হয় which Y কম্বিনেটরের মতো দেখতে খুব ভাল লাগে।