গার্ডস বনাম। যদি-তবে-হ্যাশকেলে বনাম মামলাগুলি


104

আমার তিনটি ফাংশন রয়েছে যা তালিকার নবম উপাদানটি খুঁজে পায়:

nthElement :: [a] -> Int -> Maybe a 
nthElement [] a = Nothing
nthElement (x:xs) a | a <= 0 = Nothing
                    | a == 1 = Just x
                    | a > 1 = nthElement xs (a-1)

nthElementIf :: [a] -> Int -> Maybe a
nthElementIf [] a = Nothing
nthElementIf (x:xs) a = if a <= 1
                        then if a <= 0 
                             then Nothing
                             else Just x -- a == 1
                        else nthElementIf xs (a-1)                           

nthElementCases :: [a] -> Int -> Maybe a
nthElementCases [] a = Nothing
nthElementCases (x:xs) a = case a <= 0 of
                             True -> Nothing
                             False -> case a == 1 of
                                        True -> Just x
                                        False -> nthElementCases xs (a-1)

আমার মতে, প্রথম ফাংশনটি সর্বোত্তম বাস্তবায়ন কারণ এটি সবচেয়ে সংক্ষিপ্ত। তবে অন্য দুটি বাস্তবায়ন সম্পর্কে কি এমন কিছু রয়েছে যা তাদেরকে অগ্রাধিকারযোগ্য করে তুলবে? এবং এক্সটেনশনের মাধ্যমে, আপনি কীভাবে প্রহরী, অন্যথায় বিবৃতি এবং মামলাগুলির মধ্যে নির্বাচন করবেন?


5
আপনি caseযদি ব্যবহার করেন তবে আপনার নেস্টেড বিবৃতিগুলি ভেঙে ফেলতে পারেনcase compare a 0 of LT -> ... | EQ -> ... | GT -> ...
রায়পুঞ্জ

5
@ ইম্পিওনিয়ান: আপনার অর্থcase compare a 1 of ...
হস্তক্ষেপ

উত্তর:


121

প্রযুক্তিগত দিক থেকে, তিনটি সংস্করণই সমান।

বলা হচ্ছে, শৈলীর জন্য আমার নিয়মের নিয়মটি হ'ল আপনি যদি এটি ইংরেজি হিসাবে পড়তে পারেন ( |"কখন" | otherwiseহিসাবে " , " অন্যথায় "এবং =" হিসাবে "বা" হন " হিসাবে পড়েন ) তবে আপনি সম্ভবত কিছু করছেন ঠিক আছে।

if..then..elseআপনার যখন একটি বাইনারি শর্ত থাকে বা আপনার একটি সিদ্ধান্ত নিতে হবে তখনই is নেস্টেড- if..then..elseএক্সপ্রেশনগুলি হাস্কেলের মধ্যে খুব অস্বাভাবিক এবং এর পরিবর্তে প্রায় সবসময় রক্ষীদের ব্যবহার করা উচিত।

let absOfN =
  if n < 0 -- Single binary expression
  then -n
  else  n

প্রতিটি if..then..elseঅভিব্যক্তি কোনও ফাংশনের শীর্ষ স্তরে থাকলে একজন প্রহরী দ্বারা প্রতিস্থাপন করা যেতে পারে এবং এটি সাধারণত পছন্দ করা উচিত, কারণ আপনি আরও সহজেই আরও কেস যুক্ত করতে পারেন:

abs n
  | n < 0     = -n
  | otherwise =  n

case..ofযখন আপনার একাধিক কোড পাথ থাকে এবং প্রতিটি কোড পাথ একটি মানের কাঠামোর দ্বারা পরিচালিত হয়, যেমন প্যাটার্ন মেলানোর মাধ্যমে। আপনি খুব কমই ম্যাচ খেলেন Trueএবং False

case mapping of
  Constant v -> const v
  Function f -> map f

গার্ডগুলি পরিপূরক case..ofএক্সপ্রেশনগুলির অর্থ, আপনার যদি কোনও মানের উপর নির্ভর করে জটিল সিদ্ধান্ত নিতে হয় তবে প্রথমে আপনার ইনপুটটির কাঠামোর উপর নির্ভর করে সিদ্ধান্ত নিন এবং তারপরে কাঠামোর মানগুলিতে সিদ্ধান্ত নিন।

handle  ExitSuccess = return ()
handle (ExitFailure code)
  | code < 0  = putStrLn . ("internal error " ++) . show . abs $ code
  | otherwise = putStrLn . ("user error " ++)     . show       $ code

BTW। স্টাইলের পরামর্শ হিসাবে, / এর পরে স্টাফগুলি যদি একটি লাইনের জন্য খুব দীর্ঘ হয় বা অন্য কোনও কারণে আরও লাইন ব্যবহার করে তবে সর্বদা একটি =বা তার আগে একটি নতুন লাইন তৈরি করুন:|=|

-- NO!
nthElement (x:xs) a | a <= 0 = Nothing
                    | a == 1 = Just x
                    | a > 1 = nthElement xs (a-1)

-- Much more compact! Look at those spaces we didn't waste!
nthElement (x:xs) a
  | a <= 0    = Nothing
  | a == 1    = Just x
  | otherwise = nthElement xs (a-1)

1
"আপনি খুব কমই ম্যাচ খেলেন Trueএবং False" এমন কোনও অনুষ্ঠান রয়েছে যেখানে আপনি তা করতেন? সর্বোপরি, এই ধরণের সিদ্ধান্তটি সর্বদা একটি ifএবং রক্ষীদের সাথেও করা যেতে পারে।
বাম দিকের বাইরে

2
উদাহরণস্বরূপcase (foo, bar, baz) of (True, False, False) -> ...
dflemstr

@dflemstr এর মধ্যে আর কোনও সূক্ষ্ম পার্থক্য নেই যেমন মোনাডপ্লাসের প্রয়োজন রক্ষীদের এবং এবং যদি-তবে-না হয় তবে মনাডের একটি উদাহরণ ফেরত দেয়? কিন্তু আমি নিশ্চিত না.
জে ফ্রিটস্চ

2
@ জেফ্রিটস: guardফাংশনটির প্রয়োজনMonadPlus , তবে আমরা এখানে যা বলছি সেগুলি মতো প্রহরী | test =, যা সম্পর্কিত নয়।
বেন মিলউড

স্টাইল টিপের জন্য ধন্যবাদ, এখন এটি সন্দেহ দ্বারা নিশ্চিত হয়েছে।
ট্রুটহাইডার 17 ই

22

আমি জানি এটি স্পষ্টভাবে পুনরাবৃত্ত ফাংশনগুলির জন্য শৈলীর বিষয়ে প্রশ্ন, তবে আমি পরামর্শ দেব যে সর্বোত্তম শৈলীটি পরিবর্তে বিদ্যমান পুনরাবৃত্ত ফাংশনগুলি পুনরায় ব্যবহার করার উপায় খুঁজে পাচ্ছে।

nthElement xs n = guard (n > 0) >> listToMaybe (drop (n-1) xs)

2

এটি কেবল অর্ডার দেওয়ার বিষয় তবে আমি মনে করি এটি খুব পঠনযোগ্য এবং প্রহরীগুলির মতো একই কাঠামো রয়েছে।

nthElement :: [a] -> Int -> Maybe a 
nthElement [] a = Nothing
nthElement (x:xs) a = if a  < 1 then Nothing else
                      if a == 1 then Just x
                      else nthElement xs (a-1)

শেষেরটি অন্যটির দরকার নেই এবং যেহেতু অন্য কোনও সম্ভাবনা নেই, ফাংশনগুলিরও "সর্বশেষ অবলম্বন মামলা" হওয়া উচিত যদি আপনি কোনও কিছু মিস করেন।


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