অর্থপূর্ণ উদাহরণগুলির মাধ্যমে স্কেল চালিয়ে যাওয়া
আসুন আমরা from0to10
0 থেকে 10 পর্যন্ত পুনরাবৃত্তির ধারণাটি প্রকাশ করে যা সংজ্ঞায়িত করি :
def from0to10() = shift { (cont: Int => Unit) =>
for ( i <- 0 to 10 ) {
cont(i)
}
}
এখন,
reset {
val x = from0to10()
print(s"$x ")
}
println()
মুদ্রণ:
0 1 2 3 4 5 6 7 8 9 10
আসলে, আমাদের দরকার নেই x
:
reset {
print(s"${from0to10()} ")
}
println()
একই ফলাফল মুদ্রণ।
এবং
reset {
print(s"(${from0to10()},${from0to10()}) ")
}
println()
সমস্ত জোড়া মুদ্রণ:
(0,0) (0,1) (0,2) (0,3) (0,4) (0,5) (0,6) (0,7) (0,8) (0,9) (0,10) (1,0) (1,1) (1,2) (1,3) (1,4) (1,5) (1,6) (1,7) (1,8) (1,9) (1,10) (2,0) (2,1) (2,2) (2,3) (2,4) (2,5) (2,6) (2,7) (2,8) (2,9) (2,10) (3,0) (3,1) (3,2) (3,3) (3,4) (3,5) (3,6) (3,7) (3,8) (3,9) (3,10) (4,0) (4,1) (4,2) (4,3) (4,4) (4,5) (4,6) (4,7) (4,8) (4,9) (4,10) (5,0) (5,1) (5,2) (5,3) (5,4) (5,5) (5,6) (5,7) (5,8) (5,9) (5,10) (6,0) (6,1) (6,2) (6,3) (6,4) (6,5) (6,6) (6,7) (6,8) (6,9) (6,10) (7,0) (7,1) (7,2) (7,3) (7,4) (7,5) (7,6) (7,7) (7,8) (7,9) (7,10) (8,0) (8,1) (8,2) (8,3) (8,4) (8,5) (8,6) (8,7) (8,8) (8,9) (8,10) (9,0) (9,1) (9,2) (9,3) (9,4) (9,5) (9,6) (9,7) (9,8) (9,9) (9,10) (10,0) (10,1) (10,2) (10,3) (10,4) (10,5) (10,6) (10,7) (10,8) (10,9) (10,10)
এখন, কিভাবে এটি কাজ করে?
নেই নামক কোড , from0to10
এবং কলিং কোড । এই ক্ষেত্রে এটি ব্লকটি অনুসরণ করে reset
। কল কোডটিতে পাস করা প্যারামিটারগুলির মধ্যে একটি হল একটি রিটার্ন ঠিকানা যা কলিং কোডের কোন অংশটি এখনও কার্যকর করা হয়নি (**) দেখায়। কলিং কোডের সেই অংশটি ধারাবাহিকতা । কথিত কোড সেই প্যারামিটারটি যা সিদ্ধান্ত নেয় তা করতে পারে: এটিতে নিয়ন্ত্রণ পাস, বা উপেক্ষা করুন বা একাধিকবার কল করুন। এখানে from0to10
0..10 ব্যাপ্তির প্রতিটি পূর্ণসংখ্যার জন্য সেই ধারাবাহিকতাটিকে কল করে।
def from0to10() = shift { (cont: Int => Unit) =>
for ( i <- 0 to 10 ) {
cont(i)
}
}
কিন্তু ধারাবাহিকতা শেষ হয় কোথায়? এটি গুরুত্বপূর্ণ কারণ return
ধারাবাহিকতা থেকে শেষগুলি কল কোডটিতে নিয়ন্ত্রণ ফিরে আসে from0to10
,। স্কালায়, এটি শেষ হয় যেখানে reset
ব্লকটি শেষ হয় (*)।
এখন, আমরা দেখতে পাই যে ধারাবাহিকতাটি হিসাবে ঘোষিত হয়েছে cont: Int => Unit
। কেন? আমরা from0to10
হিসাবে অনুরোধ val x = from0to10()
, এবং Int
মান যে প্রকার যায় x
। Unit
এর মানে হল যে ব্লকের পরে reset
অবশ্যই কোনও মূল্য ফেরত দেওয়া হবে না (অন্যথায় কোনও ধরণের ত্রুটি হবে)। সাধারণভাবে, 4 ধরণের স্বাক্ষর রয়েছে: ফাংশন ইনপুট, ধারাবাহিকতা ইনপুট, ধারাবাহিকতা ফলাফল, ফাংশন ফলাফল। চারটি অবশ্যই অনুরোধ প্রসঙ্গে মেলে।
উপরে, আমরা মানগুলির জোড়া মুদ্রণ করেছি। আসুন আমরা গুণ টেবিল মুদ্রণ করি। কিন্তু কিভাবে আমরা \n
প্রতিটি সারির পরে আউটপুট করব ?
ক্রিয়াকলাপটি back
আমাদের নির্দিষ্ট করতে দেয় যখন নিয়ন্ত্রণটি ফিরে আসে তখন কী করা উচিত, যা ধারাবাহিকতা থেকে কোড বলে to
def back(action: => Unit) = shift { (cont: Unit => Unit) =>
cont()
action
}
back
প্রথমে এর ধারাবাহিকতা কল করে এবং তারপরে ক্রিয়াটি সম্পাদন করে ।
reset {
val i = from0to10()
back { println() }
val j = from0to10
print(f"${i*j}%4d ")
}
এটি প্রিন্ট করে:
0 0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9 10
0 2 4 6 8 10 12 14 16 18 20
0 3 6 9 12 15 18 21 24 27 30
0 4 8 12 16 20 24 28 32 36 40
0 5 10 15 20 25 30 35 40 45 50
0 6 12 18 24 30 36 42 48 54 60
0 7 14 21 28 35 42 49 56 63 70
0 8 16 24 32 40 48 56 64 72 80
0 9 18 27 36 45 54 63 72 81 90
0 10 20 30 40 50 60 70 80 90 100
ঠিক আছে, এখন সময় এসেছে কিছু মস্তিষ্কের ঝাঁকুনির জন্য। এর দুটি আমন্ত্রণ রয়েছে from0to10
। প্রথমটির ধারাবাহিকতা কী from0to10
? এটা তোলে নামোচ্চারণের অনুসরণ from0to10
মধ্যে বাইনারি কোড , কিন্তু সোর্স কোডে এটি নিয়োগ বিবৃতি অন্তর্ভুক্ত val i =
। এটি যেখানে reset
ব্লকটি শেষ হয় সেখানেই শেষ হয় তবে ব্লকের প্রান্তটি reset
নিয়ন্ত্রণে ফিরে আসে না from0to10
। শেষে reset
ব্লক আয় 2nd থেকে নিয়ন্ত্রণ from0to10
করে ঘুরে অবশেষে নিয়ন্ত্রণ ফেরৎ, back
এবং তা হয়ে যায় back
যে আয় প্রথম আবাহন করার নিয়ন্ত্রণ from0to10
। প্রথম (হ্যাঁ! প্রথম!) from0to10
প্রস্থান করলে পুরো reset
ব্লকটি বের হয় ex
নিয়ন্ত্রণ ফিরে ফেরত এ জাতীয় পদ্ধতিটিকে ব্যাকট্র্যাকিং বলা হয় , এটি একটি খুব পুরানো কৌশল, যা অন্তত প্রোলোগ এবং এআই-ওরিয়েন্টেড লিস্প ডেরিভেটিভসের সময় থেকে জানা যায়।
নাম reset
এবং shift
ভুল নাম । এই নামগুলি বিটওয়াইজ অপারেশনের জন্য আরও ভাল করা উচিত ছিল। reset
ধারাবাহিকতা সীমানা সংজ্ঞায়িত করে, এবং shift
কল স্ট্যাক থেকে একটি ধারাবাহিকতা নেয়।
মন্তব্য)
(*) স্কালায়, reset
ব্লকটি শেষ হয় যেখানে ধারাবাহিকতা শেষ হয়। আর একটি সম্ভাব্য পন্থা হ'ল ফাংশনটি যেখানে শেষ হয় সেখানেই এটি শেষ হওয়া উচিত।
(**) বলা কোডের প্যারামিটারগুলির মধ্যে একটি হল একটি রিটার্ন ঠিকানা যা দেখায় যে কলিং কোডের কোন অংশটি এখনও কার্যকর হয়নি। ঠিক আছে, স্কালায়, তার জন্য ফেরত ঠিকানাগুলির একটি ক্রম ব্যবহৃত হয়। কতগুলো? reset
ব্লকের প্রবেশের পর থেকে কল স্ট্যাকের সমস্ত ফিরিয়ে দেওয়া ঠিকানা ।
ইউপিডি পার্ট 2
ছাড়ার ধারাবাহিকতা: ফিল্টারিং
def onEven(x:Int) = shift { (cont: Unit => Unit) =>
if ((x&1)==0) {
cont()
}
}
reset {
back { println() }
val x = from0to10()
onEven(x)
print(s"$x ")
}
এই মুদ্রণ:
0 2 4 6 8 10
আসুন আমরা দুটি গুরুত্বপূর্ণ ক্রিয়াকলাপ নির্ণয় করি: ধারাবাহিকতা ( fail()
) এড়িয়ে দেওয়া এবং এটিতে নিয়ন্ত্রণ ( ) প্রবেশ করানো succ()
:
def fail() = shift { (cont: Unit => Unit) => }
def succ():Unit @cpsParam[Unit,Unit] = { }
উভয় সংস্করণ succ()
(উপরে) কাজ। দেখা যাচ্ছে যে shift
একটি মজার স্বাক্ষর রয়েছে এবং যদিও succ()
কিছুই না করে তবে টাইপ ব্যালেন্সের জন্য অবশ্যই তার স্বাক্ষর থাকতে হবে।
reset {
back { println() }
val x = from0to10()
if ((x&1)==0) {
succ()
} else {
fail()
}
print(s"$x ")
}
যেমনটি প্রত্যাশিত, এটি প্রিন্ট করে
0 2 4 6 8 10
একটি ফাংশনের মধ্যে, succ()
প্রয়োজনীয় নয়:
def onTrue(b:Boolean) = {
if(!b) {
fail()
}
}
reset {
back { println() }
val x = from0to10()
onTrue ((x&1)==0)
print(s"$x ")
}
আবার, এটি মুদ্রণ
0 2 4 6 8 10
এখন, এর onOdd()
মাধ্যমে আমাদের সংজ্ঞা দিন onEven()
:
class ControlTransferException extends Exception {}
def onOdd(x:Int) = shift { (cont: Unit => Unit) =>
try {
reset {
onEven(x)
throw new ControlTransferException()
}
cont()
} catch {
case e: ControlTransferException =>
case t: Throwable => throw t
}
}
reset {
back { println() }
val x = from0to10()
onOdd(x)
print(s"$x ")
}
উপরে, x
এমনকি যদি হয়, একটি ব্যতিক্রম নিক্ষেপ করা হয় এবং ধারাবাহিকতা বলা হয় না; যদি x
বিজোড় হয় তবে ব্যতিক্রম নিক্ষেপ করা হয় না এবং ধারাবাহিকতা বলা হয়। উপরের কোড মুদ্রণ:
1 3 5 7 9