ছোট ওয়ার্ডের জন্য স্ট্যাক জাগলিং ঠিক আছে। কোনো ওয়ার্ডে যখন একাধিক ইনপুট থাকে আর সেগুলোকে নাম ধরে ডাকতে হয়, তখন Factor দেয় লোকাল, অর্থাৎ নামযুক্ত বাইন্ডিং, যেগুলো চালু করা হয় :: (ওয়ার্ড ডিফিনিশনের জন্য) বা [| | ] (ইনলাইন ল্যাম্বডার জন্য) দিয়ে।
:: ( inputs -- outputs ): এর জায়গায় :: বসালে ইনপুটের নামগুলোই বডির ভেতরে লোকাল ভ্যারিয়েবল হয়ে যায়:
USING: locals ;
:: hypotenuse ( a b -- c )
a a *
b b *
+ sqrt ;
এবার স্ট্যাক এলোমেলো করে করা সংস্করণটির সঙ্গে তুলনা করুন:
! DOCTEST: SKIP (shown for comparison — would re-define hypotenuse)
: hypotenuse ( a b -- c )
[ sq ] bi@ + sqrt ;
দুটোই বৈধ। কোনো ইনপুট একাধিকবার ব্যবহার হলে, বা কাজের ক্রম স্বাভাবিকভাবে স্ট্যাকের ক্রমের সঙ্গে না মিললে, লোকাল সবচেয়ে ভালো কাজ করে।
:> দিয়ে মধ্যবর্তী মান বাইন্ড করা:: বডির ভেতরে (বা ইনলাইন [| ... |] ল্যাম্বডায়) :> ডেটা স্ট্যাক থেকে একটি মান তুলে নিয়ে নতুন একটি লোকালে বাইন্ড করে:
value :> name ! immutable binding
value :> name! ! mutable binding (name! is its setter)
অপরিবর্তনীয় রূপটিই বেশি ব্যবহৃত হয়। এটি দিয়ে কোনো মধ্যবর্তী মানের নাম দিন, যাতে বডিটা উপর থেকে নিচে পড়া যায়:
USING: locals math ;
:: average-3 ( x y z -- avg )
x y + z + :> sum
sum 3 / ;
! যুক্ত রূপটি লোকালটিকে পরিবর্তনযোগ্য ঘোষণা করে; পরে বডির ভেতরে value name! (কোলন নেই, :> নেই) দিয়ে সেটির মান আবার বসানো হয়:
USING: kernel locals math math.order ;
:: clamped ( x lo hi -- y )
x :> v!
v lo < [ lo v! ] when
v hi > [ hi v! ] when
v ;
পরের অনুশীলনীগুলোতে যেসব ইটারেশন ওয়ার্ডের সঙ্গে পরিচয় হবে (যেমন while), সেখানে পরিবর্তনযোগ্য লোকাল সবচেয়ে ভালো কাজ করে।
[let দিয়ে যেকোনো জায়গা থেকেই স্কোপ তৈরি:> কেবল একটি লেক্সিকাল স্কোপের ভেতরেই কাজ করে, আর :: ও [| ... |] নিজে থেকেই সেই স্কোপ তৈরি করে দেয়। সাধারণ : ওয়ার্ড থেকে বা লিসেনার থেকে লোকাল চালু করতে হলে কোডটি [let ... ] দিয়ে মুড়ে দিন:
[let code :> name code :> name ... body ]
প্রতিটি :> name আগের এক্সপ্রেশনের স্ট্যাকের একদম উপরের মানটি বাইন্ড করে; ফর্মের বাকি অংশ সেই বাইন্ডিংগুলো দেখতে পায়।
USING: locals math ;
[let 3 :> x 4 :> y x x * y y * + ] . ! => 25
স্ট্যাক-ধাঁচের : ডিফিনিশন আর নামযুক্ত বাইন্ডিংয়ের মধ্যে সেতু হলো [let। কোনো ওয়ার্ডের কেবল একটি অংশে যদি লোকাল থেকে সুবিধা হয়, তখন এটি বেশ কাজে লাগে।
[| inputs | body ]
একটি কোয়োটেশনের ভেতরে [| inputs | body ] এমন লোকাল চালু করে, যেগুলোকে বডি নাম ধরে ব্যবহার করতে পারে। assoc-map-এর মতো হায়ার-অর্ডার ওয়ার্ডের সঙ্গে এটি বিশেষভাবে কাজে লাগে, যার কোয়োটেশন key এবং value পায়:
USING: assocs locals ;
H{ { "a" 1 } { "b" 2 } }
[| key value | key value neg ] assoc-map .
! => H{ { "a" -1 } { "b" -2 } }
একই ধরনটি কাজ করে map-index-এর ক্ষেত্রেও ([sequences][sequences] ভোকাবুলারিতে), যার কোয়োটেশন এলিমেন্ট এবং তার ইনডেক্স পায়। নামগুলো স্পষ্ট করে দেয় কোন অপারেন্ড কোন ভূমিকা নেয়:
USING: locals sequences ;
! Divide each element by its 1-based position:
{ 10 80 270 } [| elt i | elt i 1 + / ] map-index .
! => { 10 40 90 }
ল্যাম্বডার স্ট্যাক ইফেক্ট নির্ধারিত হয় ইনপুট তালিকা এবং তার বডি কী তৈরি করে তা দিয়ে।
লোকাল ব্যবহার করবেন যখন:
dup/swap/rot পড়তে কষ্ট হয়।assoc-map-এ)।বডি যখন সহজ সরলরৈখিক প্রবাহ, তখন সাধারণ : ডিফিনিশনই ছোট থাকে এবং পড়ার যোগ্যতায় অন্তত সমান।
assoc-map: একবারে একটি এন্ট্রিassoc-map (assocs ভোকাবুলারিতে) একটি অ্যাসোসিয়েটিভ কালেকশনের প্রতিটি এন্ট্রির উপর একটি কোয়োটেশন ম্যাপ করে:
assoc-map ( assoc quot: ( key value -- newkey newvalue ) -- newassoc )
কোয়োটেশন লেখার সবচেয়ে পরিচ্ছন্ন উপায় হলো লোকাল ল্যাম্বডা।
cond আবার দেখাf অথবা কোনো সংখ্যামান অনুযায়ী কাজ ভাগ করতে হলে cond-ই একেবারে ঠিক। এখানে case লাগে না, কারণ তুলনা করার মতো একটিমাত্র মান নেই।
আপনি আবার রান্নাঘরে ফিরেছেন, লিয়ার সুস্বাদু লাসানিয়ার রেসিপিটি আরও নিখুঁত করতে। এখানকার কাজগুলোতে একসাথে বেশ কয়েকটি ইনপুট সামলাতে হবে, আর ঠিক তখনই লোকাল, অর্থাৎ Factor-এর নামযুক্ত বাইন্ডিং, কাজে আসে।
cooking-status ডিফাইন করুন, যা স্ট্যাক থেকে একটি টাইমার রিডিং নেয় এবং একটি স্ট্যাটাস স্ট্রিং রিটার্ন করে।
0 → "Lasagna is done."
f (টাইমার কখনো সেট করা হয়নি) → "You forgot to set the timer."
"Not done, please wait."
12 cooking-status . ! => "Not done, please wait."
0 cooking-status . ! => "Lasagna is done."
f cooking-status . ! => "You forgot to set the timer."
preparation-time ডিফাইন করুন, যা লেয়ারের নামের একটি অ্যারে এবং প্রতি লেয়ারে মিনিটের একটি গড় সংখ্যা নেয়, আর মোট প্রস্তুতির সময় রিটার্ন করে।
{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } 3 preparation-time .
! => 18
quantities ডিফাইন করুন, যা লেয়ারের নামের একটি অ্যারে নেয় এবং দুটি মান রিটার্ন করে: প্রয়োজনীয় নুডলসের গ্রাম (প্রতি নুডলস লেয়ারে 50 g) এবং প্রয়োজনীয় সসের লিটার (প্রতি সস লেয়ারে 1/5 লিটার)।
{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } quantities .s
! => 100
! => 2/5
আপনার বন্ধু উপকরণের একটি তালিকা পাঠায়; তালিকার শেষ আইটেমটিই তার গোপন উপকরণ। add-secret-ingredient ডিফাইন করুন, যা তার তালিকা ও আপনার তালিকা নেয় এবং শেষে গোপন উপকরণটি যোগ করা আপনার তালিকাটি রিটার্ন করে।
{ "noodles" "sauce" "mozzarella" "kampot pepper" }
{ "noodles" "meat" "sauce" "mozzarella" }
add-secret-ingredient .
! => { "noodles" "meat" "sauce" "mozzarella" "kampot pepper" }
রান্নার বইয়ের রেসিপিতে দুই পোরশন হয়। scale-recipe ডিফাইন করুন, যা একটি রেসিপি (উপকরণের নাম থেকে পরিমাণে একটি হ্যাশটেবিল) এবং পোরশনের লক্ষ্য সংখ্যা নেয়, আর সেই অনুপাতে স্কেল করা একটি নতুন রেসিপি রিটার্ন করে।
H{ { "noodles" 200 } { "sauce" 1/2 } { "mozzarella" 1 } { "meat" 100 } }
4 scale-recipe .
! => H{ { "noodles" 400 } { "sauce" 1 } { "mozzarella" 2 } { "meat" 200 } }
Exercism-এ সাইন আপ করুন, Factor ট্র্যাকের 47টি কনসেপ্ট163টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।