স্কেলার ধারাবাহিকতা কী কী এবং সেগুলি কেন ব্যবহার করবেন?


85

আমি সবে স্ক্যালায় প্রোগ্রামিং শেষ করেছি এবং আমি স্কালার ২.7 থেকে ২.৮ এর মধ্যে পরিবর্তনগুলি সন্ধান করছি। যেটিকে সবচেয়ে গুরুত্বপূর্ণ বলে মনে হচ্ছে তা হচ্ছে ধারাবাহিকতা প্লাগইন, তবে এটি কী জন্য কার্যকর বা এটি কীভাবে কাজ করে তা আমি বুঝতে পারি না। আমি দেখেছি এটি অ্যাসিক্রোনাস আই / ওয়ের পক্ষে ভাল, তবে কেন তা জানতে পারি নি। বিষয়টিতে আরও কয়েকটি জনপ্রিয় সংস্থানগুলি হ'ল:

এবং স্ট্যাক ওভারফ্লো এই প্রশ্ন:

দুর্ভাগ্যক্রমে, এই রেফারেন্সগুলির মধ্যে কোনটিই ধারাবাহিকতাগুলির জন্য বা শিফট / রিসেট ফাংশনগুলি কী করণীয় তা নির্ধারণ করার চেষ্টা করে না এবং আমি কোনও রেফারেন্স পাইনি। লিঙ্কযুক্ত নিবন্ধগুলির উদাহরণগুলির মধ্যে কোনওটি কীভাবে কাজ করে (বা তারা কী করে) কীভাবে কাজ করে তা অনুমান করতে সক্ষম হয়ে উঠছি না, সুতরাং আমাকে সাহায্য করার এক উপায় হতে পারে সেই নমুনাগুলির মধ্যে একটির মধ্য দিয়ে লাইনে যাওয়া to এমনকি এই তৃতীয় নিবন্ধ থেকে একটি সহজ:

reset {
    ...
    shift { k: (Int=>Int) =>  // The continuation k will be the '_ + 1' below.
        k(7)
    } + 1
}
// Result: 8

ফলাফল 8 কেন? এটি সম্ভবত আমাকে শুরু করতে সহায়তা করবে।


উত্তর:


38

আমার ব্লগটি কী resetএবং কী তা ব্যাখ্যা করে shiftযাতে আপনি এটি আবার পড়তে চাইতে পারেন।

আরেকটি ভাল উত্স, যা আমি আমার ব্লগেও ইঙ্গিত করেছি, তা হল ধারাবাহিকতা পাস করার শৈলীতে উইকিপিডিয়া এন্ট্রি । এটি একটি, এখন পর্যন্ত এই বিষয়ে সবচেয়ে স্পষ্ট, যদিও এটি স্কাল সিনট্যাক্স ব্যবহার করে না, এবং ধারাবাহিকতা স্পষ্টভাবে পাস করা হয়েছে।

সীমাবদ্ধ ধারাবাহিকতার উপর থাকা কাগজটি, যা আমি আমার ব্লগে লিঙ্ক করি তবে মনে হয় এটি ভেঙে গেছে, ব্যবহারের বহু উদাহরণ দেয়।

তবে আমি মনে করি সীমিত ধারাবাহিকতার ধারণার সর্বোত্তম উদাহরণ হ'ল স্কেলা সোর্ম ar এতে, পাঠাগারটি আপনার কোডের সম্পাদন এক পর্যায়ে থামিয়ে দেয় এবং বাকী গণনাটি ধারাবাহিকতায় পরিণত হয়। লাইব্রেরিটি তখন কিছু করে - এই ক্ষেত্রে, অন্য হোস্টে গণনা স্থানান্তর করে, এবং ফলাফলটি (পরিবর্তনশীলটির মান যা অ্যাক্সেস করা হয়েছিল) যে গণনায় বন্ধ হয়েছিল তা ফিরিয়ে দেয়।

এখন, আপনি Scala পৃষ্ঠাতে এমনকি সহজ উদাহরণ বুঝতে পারছি না, তাই না আমার ব্লগ পড়ুন। এটিতে আমি কেবল এই মূল বিষয়গুলি ব্যাখ্যা করার সাথে সম্পর্কিত, ফলাফল কেন 8


আমি আপনার ব্লগ এন্ট্রিটি পুনরায় পড়ি এবং এবার আমি এটির সাথে আটকে গেলাম - আমার মনে হয় আমার কী চলছে তা সম্পর্কে আরও ভাল ধারণা আছে। আমি উইকিপিডিয়া পৃষ্ঠা থেকে খুব বেশি পাইনি (আমি ইতিমধ্যে লিস্পের ধারাবাহিকতা জানি) তবে পুনরায় সেট / শিফট স্থগিত শৈলী বা যাই হোক না কেন এটি আমাকে স্ট্যাম্প করেছিল। অধৈর্য (অর্থাত্ আমার নিজের) জন্য আপনার বিবরণ ঠিক ছিল তবে লোকেরা এটির সাথে অবশ্যই এটি আটকে রাখতে হবে "রিসেটের ফলাফলটি শিফটের অভ্যন্তরের কোডের ফলাফল" " অনুচ্ছেদ ... আমি আশাবাদী যে বিন্দু অবধি হারিয়েছিলাম কিন্তু এটি পরিষ্কার হয়ে যায়! আমি ঝাঁক ঝাঁকুনির দিকে নজর রাখব কারণ আমি এখনও কি কৌতুহল করছি এটি কীসের জন্য। ধন্যবাদ!
ডেভ

হ্যাঁ, জিনিসগুলি বুদ্ধিমান হওয়া শুরু হওয়া পর্যন্ত এটি সময় নেয় না। আমি মনে করি না যে আমি ব্যাখ্যাটি আরও দ্রুত তৈরি করে পালাতে পারি।
ড্যানিয়েল সি সোব্রাল

: (ভেরিয়েবল এবং বিবৃতি অন্তর্ভুক্ত করা অর্থাত।) এটা সব আমার জন্য একসাথে আসে যখন আমি উপলব্ধি আসেন যে, "রিসেট ধারাবাহিকতা পরিধি delimits।
JeffV

4
আপনার ব্যাখ্যাটি ভার্জোজ ছিল এবং বোঝার সারমর্মটি পায় নি। উদাহরণগুলি দীর্ঘ ছিল, প্রথম অনুচ্ছেদে আমি এগুলি পড়তে অনুপ্রাণিত করার মতো পর্যাপ্ত বুঝতে পেলাম না। সুতরাং আমি এটি ভোট দিয়েছি। আমার ভোট দেওয়ার পরে একটি চিত্র প্রদর্শন করে এসও, আমাকে একটি মন্তব্য যুক্ত করতে বলছে, তাই আমি মেনে চলছি। আমার খোলামেলা জন্য ক্ষমা।
শেলবি মুর তৃতীয়

4
আমি নিয়ন্ত্রণ প্রবাহ (বাস্তবায়নের বিশদ আলোচনা না করে) বোঝার উপর দৃষ্টি নিবদ্ধ করে এই সম্পর্কে ব্লগ করেছি। whonullpPoint.com/2014/04/scala-continuations.html
আলেকজান্দ্রোস

31

আমি ধারণাটি ব্যাখ্যা করার ক্ষেত্রে বিদ্যমান ব্যাখ্যাগুলি আশা করি তার চেয়ে কম কার্যকর বলে আমি পেয়েছি। আমি আশা করি এটি পরিষ্কার (এবং সঠিক।) আমি এখনও ধারাবাহিকতা ব্যবহার করি নি।

যখন একটি ধারাবাহিকতা ফাংশন cfবলা হয়:

  1. এক্সিকিউশনটি বাকি shiftব্লকটি এড়িয়ে যায় এবং এর শেষে আবার শুরু হয়
    • প্যারামিটারটি পাস করার cfসাথে সাথে shiftব্লকটি "নির্ধারণ করে" এক্সিকিউশন চালিয়ে যেতে থাকে। এটি প্রতিটি কলের জন্য আলাদা হতে পারেcf
  2. resetব্লকটি শেষ না হওয়া অবধি কার্যকর করা হয় (বা resetকোনও ব্লক না থাকলে কল করার আগে পর্যন্ত )
    • resetব্লকের ফলাফল (বা resetকোনও ব্লক না থাকলে প্যারামিটার ) (যা কোনও ব্লক না থাকলে) cfসেগুলিই প্রদান করে
  3. ব্লক cfশেষ হওয়া অবধি কার্যকরকরণ অব্যাহত থাকেshift
  4. এক্সিকিউশনটি resetব্লকের সমাপ্তি অবধি এড়িয়ে যায় (বা পুনরায় সেট করার জন্য একটি কল?)

সুতরাং এই উদাহরণে, এ থেকে জেড পর্যন্ত বর্ণগুলি অনুসরণ করুন

reset {
  // A
  shift { cf: (Int=>Int) =>
    // B
    val eleven = cf(10)
    // E
    println(eleven)
    val oneHundredOne = cf(100)
    // H
    println(oneHundredOne)
    oneHundredOne
  }
  // C execution continues here with the 10 as the context
  // F execution continues here with 100
  + 1
  // D 10.+(1) has been executed - 11 is returned from cf which gets assigned to eleven
  // G 100.+(1) has been executed and 101 is returned and assigned to oneHundredOne
}
// I

এই মুদ্রণ:

11
101

4
আমি যখন এটি সংকলন করার চেষ্টা করেছি তখন "সিপিএস-রুপান্তরিত ফাংশন ফলাফলের জন্য গণনা টাইপ করতে পারি না" বলে আমি ত্রুটি পেয়েছি .. এটি কীভাবে ঠিক করা যায় তা আমি নিশ্চিত নই
ফ্যাবিও ভেরোনেজ

@ ফ্যাবিও ভেরোনজ শিফটের শেষে একটি রিটার্নের বিবৃতি যুক্ত করুন: println(oneHundredOne) }বলুন, এ পরিবর্তন করুন println(oneHundredOne); oneHundredOne }
ফলোনে

একটি ভয়ঙ্কর বাক্য গঠনের জন্য দুর্দান্ত ব্যাখ্যা। ধারাবাহিকতা ক্রিয়াকলাপের ঘোষণাটি তার শরীর থেকে অদ্ভুতভাবে পৃথক। আমি অন্যদের সাথে এই জাতীয় মাথা-স্ক্র্যাচিং কোডটি ভাগ করে নিতে নারাজ।
জোয়েটউইল

cannot compute type for CPS-transformed function resultত্রুটি এড়াতে +1অবিলম্বে অনুসরণ করা উচিত oneHundredOne}। বর্তমানে তাদের মধ্যে থাকা মন্তব্যগুলি কোনওভাবে ব্যাকরণকে ভেঙে দেয়।
lcn

9

স্কালার বিস্মৃত ধারাবাহিকতার জন্য গবেষণামূলক গবেষণাপত্র থেকে প্রামাণ্য উদাহরণ দেওয়া হয়েছে , কিছুটা পরিবর্তন করা হয়েছে যাতে ফাংশন ইনপুটটির shiftনাম দেওয়া হয় fএবং এভাবে আর বেনামে থাকে না।

def f(k: Int => Int): Int = k(k(k(7)))
reset(
  shift(f) + 1   // replace from here down with `f(k)` and move to `k`
) * 2

Scala প্লাগ ইন রূপান্তরগুলির এই উদাহরণে যেমন যে গণনার (ইনপুট যুক্তি মধ্যে reset) প্রতিটি থেকে শুরু shiftনামোচ্চারণের করতে resetহয় প্রতিস্থাপিত ফাংশন (যেমন সঙ্গে f) ইনপুট shift

প্রতিস্থাপিত গণনা একটি ফাংশনে স্থানান্তরিত হয় (অর্থাত্ সরানো) k। ফাংশন fফাংশন ইনপুট k, যেখানে k রয়েছে প্রতিস্থাপিত গণনার, kইনপুট x: Int, এবং গণনার kপ্রতিস্থাপন shift(f)সঙ্গে x

f(k) * 2
def k(x: Int): Int = x + 1

যার একই প্রভাব রয়েছে:

k(k(k(7))) * 2
def k(x: Int): Int = x + 1

নোট করুন Intইনপুট প্যারামিটারের xধরণ (যেমন প্রকারের স্বাক্ষর k) এর ইনপুট প্যারামিটারের স্বাক্ষর দ্বারা দেওয়া হয়েছিল f

ধারণাগুলি সমতুল্য বিমূর্ততা সহ আরও ধার করা উদাহরণ, অর্থাত readএতে ফাংশন ইনপুট shift:

def read(callback: Byte => Unit): Unit = myCallback = callback
reset {
  val byte = "byte"

  val byte1 = shift(read)   // replace from here with `read(callback)` and move to `callback`
  println(byte + "1 = " + byte1)
  val byte2 = shift(read)   // replace from here with `read(callback)` and move to `callback`
  println(byte + "2 = " + byte2)
}

আমি বিশ্বাস করি এটির যৌক্তিক সমতুল্যে অনুবাদ করা হবে:

val byte = "byte"

read(callback)
def callback(x: Byte): Unit {
  val byte1 = x
  println(byte + "1 = " + byte1)
  read(callback2)
  def callback2(x: Byte): Unit {
    val byte2 = x
    println(byte + "2 = " + byte1)
  }
}

আমি আশা করি যে এটি সুসংগত সাধারণ বিমূর্ততাটিকে ব্যাখ্যা করেছে যা এই দুটি উদাহরণের পূর্ববর্তী উপস্থাপনার দ্বারা কিছুটা বিস্মৃত হয়েছিল। উদাহরণস্বরূপ, ক্যানোনিকাল প্রথম উদাহরণে উপস্থাপিত হয়েছিল গবেষণা কাগজ একটি বেনামী ফাংশন হিসাবে, আমার নামে পরিবর্তে f, এইভাবে তা অবিলম্বে কিছু পাঠকদের এটি abstractly অনুরূপ ছিল পরিষ্কার করা হয় নি readধার দ্বিতীয় উদাহরণ।

এইভাবে সীমানাবদ্ধ ধারাবাহিকতা "আপনি আমাকে বাইরে ডাকেন reset" থেকে "আমি আপনাকে ভিতরে ডাকি" থেকে "ইনভারসন অফ-কন্ট্রোল" এর মায়াজাল তৈরি করে reset

রিটার্নের ধরণটি রিটার্নের ধরণের হিসাবে একই রকম হওয়া প্রয়োজন fতবে kতা নয়, resetঅর্থাত্ যতক্ষণ একই ধরণের রিটার্ন দেয় ততক্ষণ fকোনও রিটার্ন টাইপ ঘোষণা করার স্বাধীনতা রয়েছে । এর জন্য এবং ( নীচেও দেখুন) DkfresetreadcaptureENV


সীমানাযুক্ত ধারাবাহিকতা সুস্পষ্টভাবে রাষ্ট্রের নিয়ন্ত্রণকে উল্টে দেয় না, উদাহরণস্বরূপ readএবং callbackখাঁটি ফাংশন নয়। সুতরাং কলার স্বচ্ছ অভিব্যক্তিগুলি তৈরি করতে পারে না এবং এটি উদ্দেশ্যমূলক আবশ্যক শব্দার্থবিজ্ঞানের উপর ঘোষণামূলক (ওরফে স্বচ্ছ) নিয়ন্ত্রণ রাখে না

আমরা স্পষ্টতই সীমিত ধারাবাহিকতা সহ বিশুদ্ধ ফাংশন অর্জন করতে পারি।

def aread(env: ENV): Tuple2[Byte,ENV] {
  def read(callback: Tuple2[Byte,ENV] => ENV): ENV = env.myCallback(callback)
  shift(read)
}
def pure(val env: ENV): ENV {
  reset {
    val (byte1, env) = aread(env)
    val env = env.println("byte1 = " + byte1)
    val (byte2, env) = aread(env)
    val env = env.println("byte2 = " + byte2)
  }
}

আমি বিশ্বাস করি এটির যৌক্তিক সমতুল্যে অনুবাদ করা হবে:

def read(callback: Tuple2[Byte,ENV] => ENV, env: ENV): ENV =
  env.myCallback(callback)
def pure(val env: ENV): ENV {
  read(callback,env)
  def callback(x: Tuple2[Byte,ENV]): ENV {
    val (byte1, env) = x
    val env = env.println("byte1 = " + byte1)
    read(callback2,env)
    def callback2(x: Tuple2[Byte,ENV]): ENV {
      val (byte2, env) = x
      val env = env.println("byte2 = " + byte2)
    }
  }
}

স্পষ্ট পরিবেশের কারণে এটি শোরগোল পড়ছে।

তাত্পর্যপূর্ণভাবে লক্ষ্য করুন, স্কালায় হাস্কেলের বৈশ্বিক ধরণের অনুকরণ নেই এবং সুতরাং আমি জানি যতক্ষণ না কোনও রাষ্ট্রের মনোদের unit(সুস্পষ্ট পরিবেশকে আড়াল করার জন্য সম্ভাব্য কৌশল হিসাবে) উত্তোলন সমর্থন করতে পারে না , কারণ হাস্কেলের বৈশ্বিক (হিন্দি-মিলনার) টাইপ অনুকরণ হীরা একাধিক ভার্চুয়াল উত্তরাধিকার সমর্থন না উপর নির্ভর করে ।


আমি প্রস্তাব করছি যে reset/ shiftপরিবর্তন করা delimit/ replace। আর কনভেনশন দ্বারা, যে fএবং readহতে with, এবং kএবং callbackহতে replaced, captured, continuation, অথবা callback
শেলবি মুর তৃতীয়

একটি কীওয়ার্ড সহ। পিএস আপনার কয়েকটি রিসেটের () রয়েছে যা {} যাইহোক দুর্দান্ত লেখার জন্য হওয়া উচিত!
এনএফজি

@nafg আপনাকে ধন্যবাদ, তাই আমি এর replacementপরিবর্তে প্রস্তাব দেব with। আফাইক, ()অনুমতিও আছে কি? আফাইক, {}এটি " ক্লোজারগুলির জন্য স্কালার লাইটওয়েট সিনট্যাক্স" , যা অন্তর্নিহিত ফাংশন কলটি গোপন করে। উদাহরণস্বরূপ, দেখুন কীভাবে আমি ড্যানিয়েলের পুনরায়sequence লিখেছিলাম (নোট করুন যে কোডটি কখনই সংকলিত বা পরীক্ষিত হয়নি, সুতরাং দয়া করে আমাকে সংশোধন করতে দ্বিধা বোধ করবেন)।
শেলবি মুর তৃতীয়

4
একটি ব্লক - যা একাধিক বক্তব্য সম্বলিত একটি এক্সপ্রেশন - এর জন্য কোঁকড়া ধনুর্বন্ধনী প্রয়োজন।
এনএফজি

@nafg, সঠিক আফাইক shift resetলাইব্রেরির ফাংশন, কীওয়ার্ড নয়। ফাংশনটি কেবলমাত্র একটি প্যারামিটারের প্রত্যাশা করে এইভাবে {}বা ()ব্যবহার করা যেতে পারে । Scala দ্বারা-নাম পরামিতি (দেখুন অধ্যায় scala প্রোগ্রামিং, 2nd ইডি। PG এর "9.5 কন্ট্রোল abstractions"। 218), যদি প্যারামিটার ধরনের কোথায় আছে বুঝতে পারছে কাটানো যেতে পারে। আমি ধরে নিলাম এবং নাম অনুসারে নয় কারণ ব্লকটি আহ্বানের আগে মূল্যায়ন করা উচিত তবে আমার একাধিক বিবৃতি প্রয়োজন । আমার ব্যবহারটি সঠিক, কারণ এটি স্পষ্টত কোনও ফাংশনের প্রকারকে ইনপুট করে। () => ...() =>Unitreset{}shift
শেলবি মুর তৃতীয়

8

ধারাবাহিকতা একটি গণনার অবস্থা ক্যাপচার করে, পরে অনুরোধ করা হবে।

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

আমি মনে করি রিসেট এক্সপ্রেশন দ্বারা প্রত্যাবর্তিত মান হ'ল => এর পরে শিফট এক্সপ্রেশনটির ভিতরে প্রকাশের মান, তবে এ সম্পর্কে আমি নিশ্চিত নই sure

সুতরাং ধারাবাহিকতার সাথে আপনি কোনও ফাংশনে একটি বরং স্বেচ্ছাসেবী এবং অ স্থানীয় লোকাল কোডটি গুটিয়ে রাখতে পারেন। এটি অ-মানক নিয়ন্ত্রণ প্রবাহ বাস্তবায়িত করতে ব্যবহার করা যেতে পারে, যেমন করোটিনিং বা ব্যাকট্র্যাকিং।

সুতরাং ধারাবাহিকতাগুলি সিস্টেমের স্তরে ব্যবহার করা উচিত। আপনার অ্যাপ্লিকেশন কোডের মাধ্যমে এগুলি ছিটিয়ে দেওয়া দুঃস্বপ্নগুলির জন্য একটি নিশ্চিত রেসিপি হবে, যা গোটো ব্যবহার করে সবচেয়ে খারাপ স্প্যাগেটি কোডের চেয়েও খারাপ।

দাবি অস্বীকার: স্ক্যালায় ধারাবাহিকতা সম্পর্কে আমার গভীর ধারণা নেই, আমি উদাহরণগুলি দেখে এবং স্কিমের ধারাবাহিকতাগুলি জানতে পেরে কেবল অনুমান করেছি।


5

আমার দৃষ্টিকোণ থেকে, এখানে সর্বোত্তম ব্যাখ্যাটি দেওয়া হয়েছিল: http://jim-mcbeath.blogspot.ru/2010/08/delimited-continuations.html

উদাহরণগুলির মধ্যে একটি:

নিয়ন্ত্রণ প্রবাহকে আরও কিছুটা স্পষ্ট দেখতে, আপনি এই কোড স্নিপেট কার্যকর করতে পারেন:

reset {
    println("A")
    shift { k1: (Unit=>Unit) =>
        println("B")
        k1()
        println("C")
    }
    println("D")
    shift { k2: (Unit=>Unit) =>
        println("E")
        k2()
        println("F")
    }
    println("G")
}

উপরের কোডটি উত্পাদন করে এখানে:

A
B
D
E
G
F
C

1

স্কেলার ধারাবাহিকতা নিয়ে আরেকটি (আরও সাম্প্রতিক - মে 2016) নিবন্ধটি হ'ল:
" স্ক্যালায় সময় ভ্রমণ: স্কালায় সিপিএস (স্কালার ধারাবাহিকতা) " শিবাংশ শ্রীবাস্তব ( shiv4nsh) দ্বারা
এছাড়া বোঝায় জিম McBeath এর নিবন্ধ উল্লিখিত দিমিত্রি Bespalov এর উত্তর

তবে তার আগে এটি ক্রমাগত বর্ণনা দেয়:

ধারাবাহিকতা হ'ল একটি কম্পিউটার প্রোগ্রামের নিয়ন্ত্রণ অবস্থার একটি বিমূর্ত উপস্থাপনা
সুতরাং এর প্রকৃত অর্থ যা হ'ল এটি একটি ডেটা স্ট্রাকচার যা প্রক্রিয়াটির প্রয়োগের একটি নির্দিষ্ট সময়ে গণ্য প্রক্রিয়াটি উপস্থাপন করে; তৈরি ডেটা স্ট্রাকচারটি রানটাইম পরিবেশে লুকানো না হয়ে প্রোগ্রামিং ভাষা দ্বারা অ্যাক্সেস করা যায়।

এটি আরও ব্যাখ্যা করার জন্য আমাদের কাছে একটি সর্বোত্তম উদাহরণ থাকতে পারে,

বলুন আপনি ফ্রিজের সামনের রান্নাঘরে স্যান্ডউইচ নিয়ে ভাবছেন। আপনি ঠিক সেখানে একটি ধারাবাহিকতা নিন এবং এটি আপনার পকেটে আটকে দিন।
তারপরে আপনি ফ্রিজের বাইরে কিছু টার্কি এবং রুটি পেয়ে নিজেকে স্যান্ডউইচ তৈরি করুন, যা এখন কাউন্টারে বসে আছে।
আপনি নিজের পকেটে ধারাবাহিকতাটি প্রার্থনা করেন এবং আপনি নিজেকে আবার একটি ফ্রিজের সামনে দাঁড়িয়ে স্যান্ডউইচের কথা ভেবে দেখেন। তবে ভাগ্যক্রমে, কাউন্টারে একটি স্যান্ডউইচ রয়েছে এবং এটি তৈরিতে ব্যবহৃত সমস্ত উপকরণ চলে গেছে। সুতরাং আপনি এটি খাওয়া। :-)

এই বর্ণনায়, sandwichঅংশটি প্রোগ্রামের ডেটার অংশ (উদাহরণস্বরূপ, স্তূপের উপরে একটি বস্তু), এবং " make sandwich" রুটিন কল করা এবং তারপরে ফিরে আসার পরিবর্তে ব্যক্তিটিকে " make sandwich with current continuation" রুটিন বলে, যা স্যান্ডউইচ তৈরি করে এবং তারপরে মৃত্যুদন্ড কার্যকর হয় ছেড়ে দেওয়া

বলা হচ্ছে, স্কাল 2.11.0-আরসি 1 এর জন্য এপ্রিল 2014 এ ঘোষণা করা হয়েছে

নিম্নলিখিত মডিউলগুলি গ্রহণ করার জন্য আমরা রক্ষণাবেক্ষণকারীদের সন্ধান করছি: স্কেল-সুইং , স্কালাল-ধারাবাহিকতা
কোনও নতুন রক্ষণাবেক্ষণকারী না পাওয়া গেলে ২.১২ এগুলিকে অন্তর্ভুক্ত করবে না
আমরা সম্ভবত অন্যান্য মডিউলগুলি বজায় রাখব (স্কালাল-এক্সএমএল, স্কালা-পার্সার-কম্বিনেটর), তবে সহায়তাটি এখনও প্রশংসিত।


0

অর্থপূর্ণ উদাহরণগুলির মাধ্যমে স্কেল চালিয়ে যাওয়া

আসুন আমরা from0to100 থেকে 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। কল কোডটিতে পাস করা প্যারামিটারগুলির মধ্যে একটি হল একটি রিটার্ন ঠিকানা যা কলিং কোডের কোন অংশটি এখনও কার্যকর করা হয়নি (**) দেখায়। কলিং কোডের সেই অংশটি ধারাবাহিকতা । কথিত কোড সেই প্যারামিটারটি যা সিদ্ধান্ত নেয় তা করতে পারে: এটিতে নিয়ন্ত্রণ পাস, বা উপেক্ষা করুন বা একাধিকবার কল করুন। এখানে from0to100..10 ব্যাপ্তির প্রতিটি পূর্ণসংখ্যার জন্য সেই ধারাবাহিকতাটিকে কল করে।

def from0to10() = shift { (cont: Int => Unit) =>
   for ( i <- 0 to 10 ) {
     cont(i) // call the continuation
   }
}

কিন্তু ধারাবাহিকতা শেষ হয় কোথায়? এটি গুরুত্বপূর্ণ কারণ returnধারাবাহিকতা থেকে শেষগুলি কল কোডটিতে নিয়ন্ত্রণ ফিরে আসে from0to10,। স্কালায়, এটি শেষ হয় যেখানে resetব্লকটি শেষ হয় (*)।

এখন, আমরা দেখতে পাই যে ধারাবাহিকতাটি হিসাবে ঘোষিত হয়েছে cont: Int => Unit। কেন? আমরা from0to10হিসাবে অনুরোধ val x = from0to10(), এবং Intমান যে প্রকার যায় xUnitএর মানে হল যে ব্লকের পরে 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 ") // printf-like formatted i*j
}

এটি প্রিন্ট করে:

   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() // call continuation only for even numbers
  }
}
reset {
  back { println() }
  val x = from0to10()
  onEven(x)
  print(s"$x ")
}

এই মুদ্রণ:

0 2 4 6 8 10 

আসুন আমরা দুটি গুরুত্বপূর্ণ ক্রিয়াকলাপ নির্ণয় করি: ধারাবাহিকতা ( fail()) এড়িয়ে দেওয়া এবং এটিতে নিয়ন্ত্রণ ( ) প্রবেশ করানো succ():

// fail: just discard the continuation, force control to return back
def fail() = shift { (cont: Unit => Unit) => }
// succ: does nothing (well, passes control to the continuation), but has a funny signature
def succ():Unit @cpsParam[Unit,Unit] = { }
// def succ() = shift { (cont: Unit => Unit) => cont() }

উভয় সংস্করণ 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():

// negation: the hard way
class ControlTransferException extends Exception {}
def onOdd(x:Int) = shift { (cont: Unit => Unit) =>
  try {
    reset {
      onEven(x)
      throw new ControlTransferException() // return is not allowed here
    }
    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 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.