আমাকে বলা হয়েছে যে ফাংশনাল প্রোগ্রামিংয়ে একটি ব্যতিক্রম ছুঁড়ে ফেলা এবং / বা পর্যবেক্ষণ করার কথা নয়। পরিবর্তে একটি ত্রুটিযুক্ত গণনা নীচের মান হিসাবে মূল্যায়ন করা উচিত। পাইথনে (বা অন্যান্য ভাষাগুলি যা সম্পূর্ণরূপে ফাংশনাল প্রোগ্রামিংকে উত্সাহিত করে না) যখনই কোনও কিছু "খাঁটি থাকতে" ভুল হয় তখন কেউ ফিরে আসতে পারে None
(বা নীচের মান হিসাবে বিবেচিত অন্য একটি বিকল্প, যদিও None
সংজ্ঞার সাথে কঠোরভাবে মেনে চলে না) তবে করতে হবে সুতরাং প্রথমে একটি ত্রুটি পর্যবেক্ষণ করতে হবে, যেমন
def fn(*args):
try:
... do something
except SomeException:
return None
এটি কি বিশুদ্ধতা লঙ্ঘন করে? এবং যদি তাই হয় তবে এর অর্থ কি, পাইথনে খাঁটি ত্রুটিগুলি পরিচালনা করা অসম্ভব?
হালনাগাদ
তার মন্তব্যে এরিক লিপার্ট এফপিতে ব্যতিক্রমের আচরণের আরেকটি উপায় সম্পর্কে মনে করিয়ে দিলেন। যদিও আমি পাইথনে এটি বাস্তবে কখনও দেখিনি, আমি এক বছর আগে এফপি অধ্যয়ন করার সময় এটির সাথে ফিরে খেলি। এখানে কোনও- optional
সজ্জিত ফাংশন Optional
মানগুলি দেয়, যা খালি হতে পারে, সাধারণ আউটপুটগুলির জন্য পাশাপাশি ব্যতিক্রমগুলির একটি নির্দিষ্ট তালিকার জন্য (অনির্ধারিত ব্যতিক্রমগুলি এখনও মৃত্যুদন্ড কার্যকর করতে পারে)। Carry
একটি বিলম্বিত মূল্যায়ন তৈরি করে, যেখানে প্রতিটি পদক্ষেপ (বিলম্বিত ফাংশন কল) হয় Optional
পূর্ববর্তী পদক্ষেপটি থেকে একটি অজানা আউটপুট পায় এবং কেবল এটিকে পাস করে দেয়, বা অন্যথায় নিজেকে একটি নতুন উত্তীর্ণের মূল্যায়ন করে Optional
। শেষ পর্যন্ত চূড়ান্ত মান হয় হয় স্বাভাবিক বা হয় Empty
। এখানে try/except
ব্লকটি কোনও সাজসজ্জার পিছনে লুকানো রয়েছে, সুতরাং নির্দিষ্ট ব্যতিক্রমগুলি রিটার্নের ধরণের স্বাক্ষরের অংশ হিসাবে বিবেচনা করা যেতে পারে।
class Empty:
def __repr__(self):
return "Empty"
class Optional:
def __init__(self, value=Empty):
self._value = value
@property
def value(self):
return Empty if self.isempty else self._value
@property
def isempty(self):
return isinstance(self._value, BaseException) or self._value is Empty
def __bool__(self):
raise TypeError("Optional has no boolean value")
def optional(*exception_types):
def build_wrapper(func):
def wrapper(*args, **kwargs):
try:
return Optional(func(*args, **kwargs))
except exception_types as e:
return Optional(e)
wrapper.__isoptional__ = True
return wrapper
return build_wrapper
class Carry:
"""
>>> from functools import partial
>>> @optional(ArithmeticError)
... def rdiv(a, b):
... return b // a
>>> (Carry() >> (rdiv, 0) >> (rdiv, 0) >> partial(rdiv, 1))(1)
1
>>> (Carry() >> (rdiv, 0) >> (rdiv, 1))(1)
1
>>> (Carry() >> rdiv >> rdiv)(0, 1) is Empty
True
"""
def __init__(self, steps=None):
self._steps = tuple(steps) if steps is not None else ()
def _add_step(self, step):
fn, *step_args = step if isinstance(step, Sequence) else (step, )
return type(self)(steps=self._steps + ((fn, step_args), ))
def __rshift__(self, step) -> "Carry":
return self._add_step(step)
def _evaluate(self, *args) -> Optional:
def caller(carried: Optional, step):
fn, step_args = step
return fn(*(*step_args, *args)) if carried.isempty else carried
return reduce(caller, self._steps, Optional())
def __call__(self, *args):
return self._evaluate(*args).value