হাস্কেল: যেখানে বনাম


117

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

যেখানে বনাম

একটি whereধারা কেবল একটি ফাংশন সংজ্ঞা স্তরে সংজ্ঞায়িত করা যেতে পারে। সাধারণত, এটি letসংজ্ঞার ক্ষেত্রের অনুরূপ । পার্থক্য শুধুমাত্র যখন রক্ষী ব্যবহার করা হয়whereধারাটির ব্যাপ্তি সমস্ত প্রহরীদের উপর প্রসারিত। বিপরীতে, একটি letঅভিব্যক্তির সুযোগটি কেবলমাত্র বর্তমান ফাংশন ক্লজ এবং গার্ড, যদি থাকে তবে।

হাস্কেল চিট শিট

Haskell, উইকি খুব বিস্তারিত এবং বিভিন্ন ঘটনা উপলব্ধ কিন্তু এটা প্রকল্পিত উদাহরণ ব্যবহার করেছেন। আমি এর ব্যাখ্যাগুলি একটি শিক্ষানবিশকে খুব সংক্ষিপ্ত বলে মনে করি।

লেট এর সুবিধা :

f :: State s a
f = State $ \x -> y
   where y = ... x ...

Control.Monad.State

কাজ করবে না, কারণ যেখানে প্যাটার্ন মেলে f = বোঝায়, যেখানে কোনও এক্সের সুযোগ নেই। বিপরীতে, আপনি যদি লেট দিয়ে শুরু করেছিলেন, তবে আপনার কোনও সমস্যা হবে না।

হাস্কেল উইকি অ্যাডভান্সটেভস অফ লেট

f :: State s a
f = State $ \x ->
   let y = ... x ...
   in  y

যেখানে সুবিধা :

f x
  | cond1 x   = a
  | cond2 x   = g a
  | otherwise = f (h x a)
  where
    a = w x

f x
  = let a = w x
    in case () of
        _ | cond1 x   = a
          | cond2 x   = g a
          | otherwise = f (h x a)

ঘোষণা বনাম এক্সপ্রেশন

Haskell, উইকি উল্লেখ করেছেন যে কোথায় দফা ঘোষণামূলক থাকাকালীন আসুন অভিব্যক্তি ভাবপূর্ণ হয়। স্টাইল বাদে তারা কীভাবে আলাদাভাবে পারফর্ম করে?

Declaration style                     | Expression-style
--------------------------------------+---------------------------------------------
where clause                          | let expression
arguments LHS:     f x = x*x          | Lambda abstraction: f = \x -> x*x
Pattern matching:  f [] = 0           | case expression:    f xs = case xs of [] -> 0
Guards:            f [x] | x>0 = 'a'  | if expression:      f [x] = if x>0 then 'a' else ...
  1. প্রথম উদাহরণে কেন যাক সুযোগ কিন্তু কোথায় নয়?
  2. প্রথম উদাহরণটি কোথায় ব্যবহার করা সম্ভব ?
  3. কিছুগুলি বাস্তব উদাহরণগুলিতে এটি প্রয়োগ করতে পারে যেখানে ভেরিয়েবলগুলি প্রকৃত প্রকাশের প্রতিনিধিত্ব করে?
  4. প্রত্যেকটি কখন ব্যবহার করবেন তা অনুসরণ করার জন্য কোনও সাধারণ নিয়ম রয়েছে?

হালনাগাদ

এই থ্রেড পরে যারা আসে তাদের জন্য আমি এখানে সন্ধানের সেরা ব্যাখ্যাটি পেয়েছি: " হাস্কেলের একটি নম্র ভূমিকা "।

এক্সপ্রেশন দিন।

যখনই কোনও নেস্টেট বাইন্ডিংয়ের সেট প্রয়োজন হয় তখনই হাস্কেলের লেট এক্সপ্রেশনগুলি দরকারী। একটি সাধারণ উদাহরণ হিসাবে, বিবেচনা করুন:

let y   = a*b
    f x = (x+y)/y
in f c + f d

একটি লেট এক্সপ্রেশন দ্বারা নির্মিত বাইন্ডিংয়ের সেটটি পারস্পরিক পুনরাবৃত্ত হয় এবং প্যাটার্ন বাইন্ডিংগুলিকে অলস নিদর্শন হিসাবে গণ্য করা হয় (অর্থাত তারা একটি অন্তর্নিহিত বহন করে ~)। অনুমোদিত একমাত্র প্রকারের ঘোষণাগুলি হ'ল প্রকার স্বাক্ষর, ফাংশন বাইন্ডিং এবং প্যাটার্ন বাইন্ডিং।

যেখানে ক্লজ।

কখনও কখনও এটি বেশ কয়েকটি সুরক্ষিত সমীকরণের সাথে স্কোপ বাইন্ডিংগুলির পক্ষে সুবিধাজনক, যার জন্য যেখানে ক্লজ প্রয়োজন:

f x y  |  y>z           =  ...
       |  y==z          =  ...
       |  y<z           =  ...
     where z = x*x

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


9
আমি প্রথম যখন হাস্কেল শিখতে শুরু করি তখন letএবং এর মধ্যে পার্থক্য দেখে আমি হতবাক হয়ে পড়েছিলাম where। আমি মনে করি এটি বোঝার সর্বোত্তম উপায় হ'ল বুঝতে হবে যে উভয়ের মধ্যে খুব কম পার্থক্য রয়েছে, এবং তাই চিন্তার কিছু নেই। একটি খুব সাধারণ যান্ত্রিক রূপান্তর মাধ্যমে whereপদ দেওয়া অর্থ letHaskell.org/onlinereport/decls.html#sect4.4.3.2 দেখুন এই রূপান্তরটি কেবলমাত্র স্বীকৃতিসংশ্লিষ্ট সুবিধার জন্যই বিদ্যমান।
টম এলিস

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

@ টম এলিস, টম, আপনি যে লিঙ্কটি উল্লেখ করেছেন তা বোঝার চেষ্টা করছিলাম কিন্তু আমার পক্ষে এটা খুব কঠিন ছিল, আপনি কি এই সাধারণ রূপান্তরকে নিখুঁত প্রাণীর পক্ষে ব্যাখ্যা করতে পারেন?
heেগেগাস

1
@ জেগেদাস: f = body where x = xbody; y = ybody ...অর্থf = let x = xbody; y = ybody ... in body
টম এলিস

ধন্যবাদ টম! এটি অন্য পথে যেতে পারে? কোনও লেট এক্সপ্রেশনকে case .... of ... whereকীভাবে কোনও অভিব্যক্তিতে রূপান্তর করা সম্ভব ? আমি এই সম্পর্কে নিশ্চিত নই।
jhegedus

উত্তর:


39

1: উদাহরণে সমস্যা

f :: State s a
f = State $ \x -> y
    where y = ... x ...

পরামিতি হয় x। ধারাটিতে থাকা জিনিসগুলি whereকেবলমাত্র ফাংশনের প্যারামিটারগুলি f(কোনও কিছুই নেই) এবং বাইরের স্কোপের জিনিসগুলি উল্লেখ করতে পারে।

2: whereপ্রথম উদাহরণটিতে একটি ব্যবহার করতে, আপনি একটি দ্বিতীয় নামক ক্রিয়াকলাপ প্রবর্তন করতে পারেন যা এটি xপ্যারামিটার হিসাবে গ্রহণ করে :

f = State f'
f' x = y
    where y = ... x ...

বা এই মত:

f = State f'
    where
    f' x = y
        where y = ... x ...

3: ...'গুলি ব্যতীত এখানে একটি সম্পূর্ণ উদাহরণ রয়েছে :

module StateExample where

data State a s = State (s -> (a, s))

f1 :: State Int (Int, Int)
f1 = State $ \state@(a, b) ->
    let
        hypot = a^2 + b^2
        result = (hypot, state)
    in result

f2 :: State Int (Int, Int)
f2 = State f
    where
    f state@(a, b) = result
        where
        hypot = a^2 + b^2
        result = (hypot, state)

৪: কখন ব্যবহার করবেন letবা whereস্বাদের বিষয়। আমি letকোনও গণনার উপর জোর দেওয়ার জন্য (এটি সামনে সরিয়ে নিয়ে) এবং whereপ্রোগ্রাম প্রবাহকে জোর দিয়ে (পিছনে গণনাটি সরিয়ে দিয়ে) ব্যবহার করতে চাই।


2
"ক্লজটিতে যে জিনিসগুলি কেবল ফাংশনটির প্যারামিটারগুলিকে উল্লেখ করতে পারে চ (সেখানে কিছুই নেই) এবং বাইরের স্কোপের জিনিসগুলি" " - এটি আমার পক্ষে এটি স্পষ্ট করতে সহায়তা করে।

28

প্রহরীটির নির্দেশিত প্রহরীদের ক্ষেত্রে প্রযুক্তিগত পার্থক্য থাকলেও, আপনি নীচে সংজ্ঞায়িত অতিরিক্ত ভেরিয়েবলগুলি সহ মূল সূত্রটি সামনে রাখতে চান কিনা সে ক্ষেত্রেও একটি ধারণাগত পার্থক্য রয়েছে ( where) বা আপনি সমস্ত কিছু সামনে রেখে এবং সূত্রটি নির্দিষ্ট করতে চান কিনা নীচে ( let)। প্রতিটি শৈলীর আলাদা জোর থাকে এবং আপনি উভয়ই গণিতের কাগজপত্র, পাঠ্যপুস্তক ইত্যাদিতে ব্যবহৃত দেখতে পান সাধারণতঃ এমন ভেরিয়েবলগুলি যা যথেষ্ট পরিমাণে অনিচ্ছুক যে সূত্রগুলি সেগুলি ব্যতীত বোঝায় না সেগুলি উপরে বর্ণিত হওয়া উচিত; প্রসঙ্গে বা তাদের নামগুলির কারণে স্বজ্ঞাত যে পরিবর্তনগুলি নীচে সংজ্ঞায়িত করা উচিত। উদাহরণস্বরূপ, মহামান্য হ্যাভওয়ালের উদাহরণে এর অর্থ vowelsসুস্পষ্ট এবং তাই এর ব্যবহারের উপরে এটি সংজ্ঞায়িত করার দরকার নেই ( letগার্ডের কারণে কার্যকর হবে না এমন বিষয়টি উপেক্ষা করে )।


1
এটি থাম্বের একটি ভাল নিয়ম সরবরাহ করে। কোথা থেকে স্কোপ আলাদা বলে মনে হচ্ছে কেন আপনি তা বিশদভাবে বলতে পারেন?

কারণ হাস্কেল সিনট্যাক্স তাই বলে। দুঃখিত, একটি ভাল উত্তর নেই। একটি "লেট" এর অধীনে টোক করার সময় সম্ভবত শীর্ষ-স্কোপযুক্ত সংজ্ঞাগুলি পড়া শক্ত হয় যাতে এটি নিষ্ক্রিয় করা হয়।
gdj

13

আইনগত:

main = print (1 + (let i = 10 in 2 * i + 1))

আইনী নয়:

main = print (1 + (2 * i + 1 where i = 10))

আইনগত:

hasVowel [] = False
hasVowel (x:xs)
  | x `elem` vowels = True
  | otherwise = False
  where vowels = "AEIOUaeiou"

আইনী নয়: (এমএল এর বিপরীতে)

let vowels = "AEIOUaeiou"
in hasVowel = ...

13
নীচের উদাহরণগুলি বৈধ যখন আপনি অন্যান্য ব্যাখ্যা না করে ব্যাখ্যা করতে পারেন?

2
যারা জানেন না তাদের ক্ষেত্রে এটি আইনী: hasVowel = let^M vowels = "AEIOUaeiou"^M in ...( ^Mনিউলাইন)
টমাস এডিং

5

আমি LYHFGG থেকে এই উদাহরণটি সহায়ক বলে খুঁজে পেয়েছি :

ghci> 4 * (let a = 9 in a + 1) + 2  
42  

letএটি একটি এক্সপ্রেশন যাতে আপনি যে কোনও let জায়গায় (!) রাখতে পারেন যেখানে অভিব্যক্তি যেতে পারে।

অন্য কথায়, উপরের উদাহরণে কেবল প্রতিস্থাপনের জন্য ব্যবহার করা সম্ভব নয় (সম্ভবত আরও কিছু ভার্বোস অভিব্যক্তি একত্রিত না করে )।whereletcasewhere


3

দুঃখের বিষয়, এখানে বেশিরভাগ উত্তর নবজাতকের জন্য খুব প্রযুক্তিগত।

LHYFGG এর একটি সম্পর্কিত অধ্যায় রয়েছে - যা আপনার যদি ইতিমধ্যে না পড়ে থাকে তবে পড়া উচিত:

  • whereকেবলমাত্র একটি সিনট্যাকটিক কনস্ট্রাক্ট ( চিনি নয় ) যা কেবল ফাংশন সংজ্ঞাতে কার্যকর
  • let ... inএটি নিজেই একটি অভিব্যক্তি , সুতরাং আপনি যেখানে কোনও অভিব্যক্তি রাখতে পারেন সেগুলি এগুলি ব্যবহার করতে পারেন। নিজেই একটি অভিব্যক্তি হওয়ায় এটি রক্ষীদের জন্য বাধ্যতামূলক জিনিসগুলির জন্য ব্যবহার করা যায় না।

শেষ অবধি, আপনি letতালিকা বোধগম্যতেও ব্যবহার করতে পারেন :

calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi >= 25.0]
-- w: width
-- h: height

আমরা একটি তালিকা বোধের ভিতরে একটি লেট অন্তর্ভুক্ত করি যেমন আমরা ভবিষ্যদ্বাণী করব, কেবল এটি তালিকা ফিল্টার করে না, এটি কেবল নামগুলিতে আবদ্ধ। তালিকা অনুধাবনের ভিতরে একটি লেটে সংজ্ঞায়িত নামগুলি আউটপুট ফাংশন (পূর্বে অংশ |) এবং বাইন্ডিংয়ের পরে আসা সমস্ত পূর্বাভাস এবং বিভাগগুলিতে দৃশ্যমান । সুতরাং আমরা আমাদের ফাংশনটি কেবলমাত্র লোকের বিএমআই> = 25 এ ফিরিয়ে আনতে পারি:


এটি হ'ল একমাত্র উত্তর যা আসলে আমাকে পার্থক্যটি বুঝতে সাহায্য করেছিল। প্রযুক্তিগত উত্তরগুলি আরও অভিজ্ঞ হাস্কেল-এরের পক্ষে কার্যকর হতে পারে, তবে এটি আমার মতো একজন নবজাতকের পক্ষে যথেষ্ট c +1
জ্যাক জি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.