ক্ষুদ্র দোসর, ক্ষুদ্র দোভাষী


33

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

ভাষার স্পেসিফিকেশন

এই স্পেসিফিকেশনে, যার ফলাফলটি "অপরিজ্ঞাত" হিসাবে বর্ণিত হয়েছে এমন কোনও শর্ত আপনার দোভাষীতে কিছু করতে পারে: ক্র্যাশ, নিঃশব্দে ব্যর্থ হওয়া, এলোমেলো গব্বলডেগুক উত্পাদন করতে পারে, বা প্রত্যাশা অনুযায়ী কাজ করতে পারে। পাইথন 3 এ একটি রেফারেন্স বাস্তবায়ন এখানে পাওয়া যায়

বাক্য গঠন

Tinylisp মধ্যে টোকেন হয় (, )অথবা প্রথম বন্ধনী বা স্থান ব্যতীত এক বা একাধিক মুদ্রণযোগ্য ASCII অক্ষর কোন স্ট্রিং। (অর্থাত্ নিম্নোক্ত রেজেক্স:। [()]|[^() ]+) সম্পূর্ণরূপে সংখ্যার সমন্বিত কোনও টোকেন হল একটি পূর্ণসংখ্যার আক্ষরিক। (লিডিং শূন্য ঠিক আছ।) কোন টোকেন অ-সংখ্যা রয়েছে, প্রতীক এমনকি সাংখ্যিক সুদর্শন উদাহরণ পছন্দ 123abc, 3.14এবং -10। টোকেনগুলি পৃথক করার কারণে ইনসোফার ব্যতীত সমস্ত সাদা স্থান (কমপক্ষে, ASCII অক্ষরগুলি সহ) উপেক্ষা করা হবে।

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

4
tinylisp!!
()
(c b a)
(q ((1 2)(3 4)))

যে অভিব্যক্তিগুলি সুগঠিত হয় না (বিশেষত, এর সাথে মেলে না এমন প্রথম বন্ধনী) অপরিবর্তিত আচরণ দেয়। (রেফারেন্স বাস্তবায়ন স্বয়ংক্রিয়ভাবে বন্ধন বন্ধন বন্ধ করে দেয় এবং তুলনামূলকভাবে বন্ধন বন্ধন বন্ধ করে দেয়))

তথ্যের ধরণ

টিনাইলিস্পের ডেটা ধরণগুলি হল পূর্ণসংখ্যা, চিহ্ন এবং তালিকা। অন্তর্নির্মিত ফাংশন এবং ম্যাক্রোগুলি একটি ধরণের হিসাবে বিবেচিত হতে পারে, যদিও তাদের আউটপুট ফর্ম্যাটটি অপরিজ্ঞাত। একটি তালিকাতে যে কোনও ধরণের মান সংখ্যার সমন্বয় থাকতে পারে এবং গভীরভাবে গভীরভাবে বাসা বাঁধতে পারে। কমপক্ষে -2 ^ 31 থেকে 2 ^ 31-1 পর্যন্ত পূর্ণসংখ্যার সমর্থন করা উচিত।

খালি তালিকা ()- যেমন নীল হিসাবে উল্লেখ করা হয় - এবং পূর্ণসংখ্যা হ'ল 0মান যা যৌক্তিকভাবে মিথ্যা বলে বিবেচিত হয়; অন্যান্য সমস্ত পূর্ণসংখ্যা, অজানা তালিকাগুলি, বিল্টইনস এবং সমস্ত চিহ্নগুলি যৌক্তিকভাবে সত্য।

মূল্যায়ন

একটি প্রোগ্রামে প্রকাশগুলি ক্রমানুসারে মূল্যায়ন করা হয় এবং প্রত্যেকের ফলাফল স্টাডাউটে প্রেরণ করা হয় (পরে আরও আউটপুট ফর্ম্যাট করার ক্ষেত্রে)।

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

অন্তর্নির্মিত ফাংশন এবং ম্যাক্রোগুলি

টিনাইলিস্পে সাতটি অন্তর্নির্মিত কার্য রয়েছে। কোনও ক্রিয়াকলাপ তাদের কিছু ক্রিয়াকলাপ প্রয়োগ করার আগে এবং ফলাফলটি ফেরত দেওয়ার আগে এর প্রতিটি তর্ককে মূল্যায়ন করে।

  • c- কনস [ট্র্যাক্ট তালিকা]। দুটি আর্গুমেন্ট, একটি মান এবং একটি তালিকা নেয় এবং তালিকার সামনের অংশে মান যুক্ত করে প্রাপ্ত একটি নতুন তালিকা প্রদান করে।
  • h- মাথা ( গাড়ি , লিস্প পরিভাষায়)। একটি তালিকা নেয় এবং এতে প্রথম আইটেম দেয় বা শূন্য হলে শূন্য করে।
  • t- লেজ ( সিডিআর , লিস্প পরিভাষায়)। একটি তালিকা নেয় এবং নতুন আইটেমটি প্রথম আইটেম ব্যতীত সমস্ত থাকে, বা শূন্য হলে শূন্য করে।
  • s- বিয়োগ দুটি পূর্ণসংখ্যা নেয় এবং দ্বিতীয়টি প্রথম বিয়োগ করে দেয় returns
  • l- কম। দুটি পূর্ণসংখ্যা গ্রহণ করে; প্রথমটি যদি দ্বিতীয়টির চেয়ে কম হয় তবে 1 প্রদান করে otherwise
  • e- সমান. একই ধরণের দুটি মান গ্রহণ করে (উভয় পূর্ণসংখ্যা, উভয় তালিকা বা উভয় প্রতীক); দু'টি সমান হলে (বা প্রতিটি উপাদানে অভিন্ন) 1 প্রদান করে, অন্যথায় 0। সমতার জন্য বিল্টিনগুলি পরীক্ষা করা অপরিজ্ঞাত (রেফারেন্স বাস্তবায়ন প্রত্যাশার মতো কাজ করে)।
  • v- eval। একটি অভিব্যক্তি উপস্থাপন করে একটি তালিকা, পূর্ণসংখ্যা বা প্রতীক নেয় এবং তা মূল্যায়ন করে। যেমন করণ (v (q (c a b)))করাই সমান (c a b); (v 1)দেয় 1

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

টিনাইলিস্পে তিনটি অন্তর্নির্মিত ম্যাক্রো রয়েছে। কোনও ম্যাক্রো, কোনও ফাংশনের বিপরীতে, তাদের উপর ক্রিয়াকলাপ প্রয়োগের আগে তার যুক্তিগুলির মূল্যায়ন করে না।

  • q- উদ্ধৃতি। একটি অভিব্যক্তি নেয় এবং এটি মূল্যহীন প্রদান করে। উদাহরণস্বরূপ, মূল্যায়ন (1 2 3)একটি ত্রুটি দেয় কারণ এটি 1একটি ফাংশন বা ম্যাক্রো হিসাবে কল করার চেষ্টা করে তবে (q (1 2 3))তালিকাটি ফেরত দেয় (1 2 3)। মূল্যায়ন aনাম বাউন্ড মান দেয় a, কিন্তু (q a)নাম নিজেই দেয়।
  • i- যদি। তিনটি এক্সপ্রেশন নেয়: একটি শর্ত, একটি iftrue এক্সপ্রেশন এবং একটি iffalse এক্সপ্রেশন। প্রথমে শর্তটি মূল্যায়ন করে। ফলাফল মিথ্যা ( 0বা শূন্য) হলে, মূল্যায়ন করে এবং iffalse অভিব্যক্তি প্রদান করে। অন্যথায়, মূল্যায়ন করে এবং iftrue এক্সপ্রেশনটি প্রদান করে। মনে রাখবেন যে যে এক্সপ্রেশনটি ফেরত নেই তা কখনই মূল্যায়ন হয় না।
  • d- Def। একটি প্রতীক এবং একটি অভিব্যক্তি লাগে। এক্সপ্রেশনকে মূল্যায়ন করে এবং বিশ্বব্যাপী সুযোগে একটি নাম হিসাবে চিহ্নিত প্রদত্ত প্রতীকে এটি আবদ্ধ করে , তারপরে প্রতীকটি প্রত্যাবর্তন করে। একটি নাম নতুন করে সংজ্ঞায়িত করার চেষ্টা করা ব্যর্থ হওয়া উচিত (নিঃশব্দে, একটি বার্তা সহ, বা ক্রাশ করে; রেফারেন্স প্রয়োগকরণ একটি ত্রুটি বার্তা প্রদর্শন করে)। দ্রষ্টব্য: নামটি পাস করার আগে নামটি উদ্ধৃত করার প্রয়োজন নেই d, যদিও এটি তালিকা বা প্রতীক যা আপনি মূল্যায়ন করতে চান না তা যদি প্রকাশের উদ্ধৃতি দেওয়া প্রয়োজন: যেমন (d x (q (1 2 3))),।

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

ব্যবহারকারী-সংজ্ঞায়িত ফাংশন এবং ম্যাক্রোগুলি

এই দশটি বিল্ট-ইনগুলি থেকে শুরু করে, নতুন ফাংশন এবং ম্যাক্রোগুলি তৈরি করে ভাষাটি বাড়ানো যেতে পারে। এগুলির কোনও ডেডিকেটেড ডেটা টাইপ নেই; এগুলি কেবল একটি নির্দিষ্ট কাঠামোর সাথে তালিকাগুলি:

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

উদাহরণস্বরূপ, নিম্নলিখিত অভিব্যক্তিটি এমন একটি ফাংশন যা দুটি পূর্ণসংখ্যা যোগ করে:

(q               List must be quoted to prevent evaluation
 (
  (x y)          Parameter names
  (s x (s 0 y))  Expression (in infix, x - (0 - y))
 )   
)

এবং একটি ম্যাক্রো যা বেশ কয়েকটি যুক্তি গ্রহণ করে এবং প্রথমটিকে মূল্যায়ন করে এবং ফেরত দেয়:

(q
 (
  ()
  args
  (v (h args))
 )
)

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

যেহেতু ফাংশন সংস্থাগুলি সংজ্ঞা সময়ে কার্যকর করা হয় না, তাই পুনরাবৃত্ত ফাংশনগুলি সহজেই সংজ্ঞাযোগ্য:

(d len
 (q (
  (list)
  (i list                      If list is nonempty
   (s 1 (s 0 (len (t list))))  1 - (0 - len(tail(list)))
   0                           else 0
  )
 ))
)

নোট করুন, যদিও, উপরেরটি দৈর্ঘ্যের ক্রিয়াটি সংজ্ঞায়িত করার জন্য ভাল উপায় নয় কারণ এটি ব্যবহার করে না ...

টেইল-কল পুনরাবৃত্তি

টেল-কল পুনরাবৃত্তি লিস্পে একটি গুরুত্বপূর্ণ ধারণা। এটি লুপ হিসাবে নির্দিষ্ট ধরণের পুনরাবৃত্তি প্রয়োগ করে, কল স্ট্যাককে ছোট রাখে। আপনার টিনাইলিস্প দোভাষীকে অবশ্যই যথাযথ টেল-কল পুনরাবৃত্তি প্রয়োগ করতে হবে !

  • যদি কোনও ব্যবহারকারী-সংজ্ঞায়িত ফাংশন বা ম্যাক্রোর রিটার্ন এক্সপ্রেশনটি অন্য কোনও ব্যবহারকারী-সংজ্ঞায়িত ফাংশন বা ম্যাক্রোর কাছে কল হয়, আপনার দোভাষীকে সেই কলটি মূল্যায়নের জন্য পুনরাবৃত্তি ব্যবহার করা উচিত নয়। পরিবর্তে, কলের চেইনটি সমাধান না হওয়া অবধি এটি বর্তমান ফাংশন এবং যুক্তিগুলিকে নতুন ফাংশন এবং যুক্তি এবং লুপের সাথে প্রতিস্থাপন করতে হবে।
  • যদি কোনও ব্যবহারকারী-সংজ্ঞায়িত ফাংশন বা ম্যাক্রোর রিটার্ন এক্সপ্রেশন কল হয় iতবে নির্বাচিত শাখাটি অবিলম্বে মূল্যায়ন করবেন না। পরিবর্তে, এটি অন্য কোনও ব্যবহারকারী-সংজ্ঞায়িত ফাংশন বা ম্যাক্রোর কল কিনা তা পরীক্ষা করে দেখুন। যদি তাই হয় তবে উপরের মত ফাংশন এবং যুক্তিগুলি সরিয়ে আউট করুন। এটি নির্বিচারে গভীরভাবে নেস্ট করা ঘটনাগুলিতে প্রযোজ্য i

টেল পুনরুক্তি সরাসরি পুনরাবৃত্তি (একটি ফাংশন নিজে কল করে) এবং অপ্রত্যক্ষ পুনরাবৃত্তি (ফাংশন aকল ফাংশন bযা কল করে [ইত্যাদি] যা ফাংশন কল করে) উভয়ের জন্য অবশ্যই কাজ করবে a

একটি পুচ্ছ পুনরাবৃত্ত দৈর্ঘ্য ফাংশন (একটি সহায়ক ফাংশন সহ len*):

(d len*
 (q (
  (list accum)
  (i list
   (len*
    (t list)
    (s 1 (s 0 accum))
   )
   accum
  )
 ))
)
(d len
 (q (
  (list)
  (len* list 0)
 ))
)

এই প্রয়োগটি ইচ্ছামত বৃহত তালিকার জন্য কাজ করে, কেবলমাত্র সর্বোচ্চ পূর্ণসংখ্যার আকার দ্বারা সীমাবদ্ধ।

ব্যাপ্তি

ফাংশন প্যারামিটারগুলি স্থানীয় ভেরিয়েবল (আসলে ধ্রুবক, যেহেতু এগুলি সংশোধন করা যায় না)। যে ফাংশনটির সেই কলটির মূল অংশটি কার্যকর করা হচ্ছে এবং কোনও গভীর কল চলাকালীন এবং ফাংশনটি ফেরার পরে সুযোগের বাইরে রয়েছে এগুলি এগুলির মধ্যে রয়েছে। তারা বিশ্বব্যাপী সংজ্ঞায়িত নামগুলি "ছায়া" করতে পারে, যার ফলে বিশ্বব্যাপী নামটি অস্থায়ীভাবে অনুপলব্ধ হয়ে যায়। উদাহরণস্বরূপ, নিম্নলিখিত কোডটি ৪ টি নয়, ৪১ টি রিটার্ন দেয়:

(d x 42)
(d f
 (q (
  (x)
  (s x 1)
 ))
)
(f 6)

যাইহোক, নিম্নলিখিত কোডটি 41 রিটার্ন দেয় কারণ xকল স্তরে 1 কল স্তরের 2 থেকে অ্যাক্সেসযোগ্য নয়:

(d x 42)
(d f
 (q (
  (x)
  (g 15)
 ))
)
(d g
 (q (
  (y)
  (s x 1)
 ))
)
(f 6)

যে কোনও সময়ে সুযোগের একমাত্র নাম হ'ল) ​​১) বর্তমানে সম্পাদনকারী ফাংশনের স্থানীয় নাম, যদি থাকে তবে, এবং ২) বিশ্বব্যাপী নাম।

জমা দেওয়ার প্রয়োজনীয়তা

ইনপুট এবং আউটপুট

আপনার ইন্টারপ্রেটার স্ট্যান্ডিন থেকে বা স্টিডিন বা কমান্ড-লাইন আর্গুমেন্টের মাধ্যমে নির্দিষ্ট করা ফাইল থেকে প্রোগ্রামটি পড়তে পারেন। প্রতিটি অভিব্যক্তি মূল্যায়ন করার পরে, এটির প্রকাশের ফলাফলটি একটি অনুবর্তনযোগ্য নিউলাইন দিয়ে স্টাডআউটে আউটপুট করা উচিত।

  • আপনার বাস্তবায়নের ভাষার সবচেয়ে প্রাকৃতিক উপস্থাপনের জন্য পূর্ণসংখ্যাগুলি আউটপুট হওয়া উচিত। নেতিবাচক পূর্ণসংখ্যার অগ্রণী বিয়োগ চিহ্ন সহ আউটপুট হতে পারে।
  • প্রতীকগুলি স্ট্রিং হিসাবে আউটপুট হওয়া উচিত, কোনও আশেপাশের উদ্ধৃতি বা পলায়ন ছাড়াই।
  • তালিকাগুলি সমস্ত আইটেম স্পেস-বিভক্ত এবং বন্ধনীগুলিতে আবৃত হওয়াতে আউটপুট হওয়া উচিত। বন্ধনীগুলির অভ্যন্তরের একটি স্থান alচ্ছিক: (1 2 3)এবং ( 1 2 3 )উভয়ই গ্রহণযোগ্য ফর্ম্যাট।
  • অন্তর্নির্মিত ফাংশন এবং ম্যাক্রোগুলি আউটপুটিং অপরিবর্তিত আচরণ। (রেফারেন্স ব্যাখ্যাটি তাদের হিসাবে প্রদর্শিত হয় <built-in function>))

অন্যান্য

রেফারেন্স ইন্টারপ্রেটারে একটি REPL পরিবেশ এবং অন্যান্য ফাইল থেকে টিনাইলিস্প মডিউল লোড করার ক্ষমতা অন্তর্ভুক্ত; এগুলি সুবিধার জন্য সরবরাহ করা হয় এবং এই চ্যালেঞ্জের জন্য প্রয়োজন হয় না।

পরীক্ষার মামলা

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

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


"সম্পূর্ণরূপে অঙ্কগুলির সমন্বিত যে কোনও টোকেন একটি পূর্ণসংখ্যার শাব্দিক ( "বিরোধীদের মনে হচ্ছে কমপক্ষে -2 2 31 থেকে 2 ^ 31-1 পর্যন্ত পূর্ণসংখ্যার সমর্থন করা উচিত" "
msh210

3
@ এমএস 210 আসলে নয়, কারণ পূর্ববর্তীটি টোকেনের বিষয়ে কথা বলছেন যেখানে উত্তরোত্তর মানগুলি নিয়ে কথা বলছে । প্রবেশের সরাসরি কোনও উপায় -1না থাকলেও, আমি এখনও -1 করে মান -1 তৈরি করতে পারি (s 0 1)
DLosc

1
@ কর্ড্প্প প্রাসঙ্গিক উইকিপিডিয়া নিবন্ধটি পড়ার পরে , আমি এই সিদ্ধান্তে পৌঁছেছি যে বাস্তবায়নটি আসলে গতিশীলের কাছাকাছি, তবে কোনও সুযোগ নেই বাসা বাঁধে। ফাংশনে ভেরিয়েবল Fফাংশন উপলভ্য নয় Gযদি Fকল G(গতিশীল scoping মত), কিন্তু তারা ফাংশন উপলভ্য নয় Hযদি Hএকটি নেস্টেড ম ফাংশন পূর্বনির্ধারণ ভিতরে F(আভিধানিক scoping মত) - দেখতে পরীক্ষা ক্ষেত্রে 5. সুতরাং এটি কলিং "আভিধানিক "বিভ্রান্তিকর হতে পারে।
DLosc

1
এটিকে অন্যভাবে বলার জন্য: স্কোপ নেস্টিংয়ের অভাবে, একটি বাস্তবায়ন গতিশীল বা লেজিকাল স্কোপিং কৌশলটি ব্যবহার করতে পারে এবং একই ফলাফল নিয়ে আসতে পারে। যে কোনও সময়ে সুযোগের একমাত্র নাম হ'ল) ​​১) বর্তমানে সম্পাদনকারী ফাংশনের স্থানীয় নাম, যদি থাকে তবে, এবং ২) বিশ্বব্যাপী নাম। বন্ধগুলি সমর্থিত নয়। (রেফারেন্স বাস্তবায়ন কল স্ট্যাকের সাথে
মিল

1
বাধ্যতামূলক xkcd
mınxomaτ

উত্তর:


11

পাইথন 2, 685 675 660 657 646 642 640 বাইট

import sys,re
E=[]
G=zip("chtsle",[eval("lambda x,y=0:"+f)for f
in"[x]+y (x+[E])[0] x[1:] x-y +(x<y) +(x==y)".split()])
def V(e,L=E):
 while 1:
    try:return e and int("0%s"%e)
    except:A=e[1:]
    if""<e:return dict(G+L).get(e,e)
    f=V(e[0],L)
    if""<f:
     if f in"iv":t=V(A[0],L);e=(e[~bool(t)],t)[f>"u"];continue
     if"e">f:G[:]+=(A[0],V(A[1],L)),
     return A[0]
    if[]>f or f[0]:A=[V(a,L)for a in A]
    if[]>f:return f(*A)
    P,e=f[-2:];L=([(P,A)],zip(P,A))[P<""]
F=lambda x:V<x<""and"(%s)"%" ".join(map(F,x))or"%s"%x
for t in re.sub("([()])"," \\1 ",sys.stdin.read()).split():
 if")"==t:t=E.pop()
 if"("==t:E+=[],
 elif E:E[-1]+=t,
 else:print F(V(t))

STDIN থেকে ইনপুট পড়ে এবং STDOUT এ আউটপুট লিখে।

যদিও কঠোরভাবে প্রয়োজন হয় না, দোভাষা নুলারি ফাংশন এবং ম্যাক্রোগুলিকে সমর্থন করে এবং এর মাধ্যমে সম্পাদিত লেজ কলগুলি অনুকূল করে v

ব্যাখ্যা

পদান্বয়

ইনপুট পার্স করার জন্য, আমরা প্রথমে প্রতিটি ঘটনাস্থল (এবং )স্পেস দিয়ে ঘিরে ফেলেছি এবং ফলস্বরূপ স্ট্রিংটিকে শব্দের মধ্যে বিভক্ত করি; এটি আমাদের টোকেনের তালিকা দেয়। আমরা একটি অভিব্যক্তি স্ট্যাক বজায় রাখি E, যা প্রাথমিকভাবে খালি। আমরা টোকেনগুলি স্ক্যান করেছি, যাতে:

  • যদি আমাদের মুখোমুখি হয় (, আমরা এক্সপ্রেশন স্ট্যাকের শীর্ষে একটি খালি তালিকা চাপি;
  • যদি আমরা একটি মুখোমুখি হই ), আমরা এক্সপ্রেশন স্ট্যাকের শীর্ষে মানটি পপ করি এবং স্ট্যাকের উপরে এর নীচে থাকা তালিকায় এটি যুক্ত করি;
  • অন্যথায়, আমরা স্ট্রিং হিসাবে, বর্তমান টোকেনটি এক্সপ্রেশন স্ট্যাকের শীর্ষে তালিকায় সংযোজন করি (আমরা এই পর্যায়ে স্ট্রিং হিসাবে পূর্ণসংখ্যা রাখি এবং মূল্যায়নের সময় তাদের পার্স করি।)

যদি, কোনও সাধারণ টোকেন প্রক্রিয়া করার সময়, বা কারণে স্ট্যাক থেকে কোনও অভিব্যক্তি পপ করার পরে ), এক্সপ্রেশন স্ট্যাকটি খালি থাকে, আমরা একটি শীর্ষ-স্তরের এক্সপ্রেশনে থাকি এবং আমরা অন্যথায় সংযোজন, ব্যবহার করে V(), এবং মূল্যটি মূল্যায়ন করি এবং যথাযথভাবে ব্যবহার করে এর ফলাফল মুদ্রণ করুন F()

মূল্যায়ন

Gকী / মান জোড়ার তালিকা হিসাবে আমরা বিশ্ব ব্যাপ্তি বজায় রাখি । প্রাথমিকভাবে, এটিতে কেবল বিল্টিন ফাংশন রয়েছে (তবে ম্যাক্রো নয় এবং নয় v, যা আমরা ম্যাক্রো হিসাবে বিবেচনা করি), যা ল্যাম্বডাস হিসাবে প্রয়োগ করা হয়।

মূল্যায়ন ভিতরে ঘটে V(), যা, নির্ণয় করা অভিব্যক্তি লাগে e, এবং স্থানীয় সুযোগ Lকী / মান জোড়া একটি তালিকা দেখুন (একটি টপ লেভেল অভিব্যক্তি মূল্যায়নের, স্থানীয় সুযোগ খালি।) এর সাহস, যা খুব হয়, V()লাইভ একটি অসীম লুপের অভ্যন্তরে, যা আমরা পরে টেল-কল অপ্টিমাইজেশন (টিসিও) সঞ্চালন করব।

আমরা eএর প্রকার অনুসারে প্রক্রিয়া করি :

  • যদি এটি খালি তালিকা, বা কোনও স্ট্রিংকে একটি আইটি তে রূপান্তরযোগ্য হয়, আমরা অবিলম্বে এটি ফিরিয়ে দেব (সম্ভবত ইনট রূপান্তর করার পরে); অন্যথায়,

  • যদি এটি একটি স্ট্রিং হয়, আমরা এটি বিশ্বব্যাপী এবং স্থানীয় স্কোপের সমষ্টি থেকে তৈরি একটি অভিধানে সন্ধান করব up আমরা যদি কোনও সম্পর্কিত মান খুঁজে পাই তবে আমরা তা ফিরিয়ে দেব; অন্যথায়, eএকটি builtin ম্যাক্রো (অর্থাত নাম হতে হবে q, i, dবা v), এবং আমরা এটা অপরিবর্তিত ফিরে যান। অন্যথায়, যদি eস্ট্রিং না হয়,

  • eএকটি (অমানবিক) তালিকা, অর্থাত্ একটি ফাংশন কল। আমরা তালিকার প্রথম উপাদানটি, অর্থাৎ ফাংশন এক্সপ্রেশনকে V()পুনরাবৃত্তভাবে কল করার মাধ্যমে (বর্তমান স্থানীয় স্কোপ ব্যবহার করে) মূল্যায়ন করি ; আমরা ফলাফল কল f। তালিকার বাকি অংশগুলি Aহ'ল আর্গুমেন্টের তালিকা। fকেবল একটি স্ট্রিং হতে পারে, এটির ক্ষেত্রে এটি একটি বিল্টিন ম্যাক্রো (বা ফাংশন v), ল্যাম্বডা, সেক্ষেত্রে এটি একটি বিল্টিন ফাংশন বা একটি তালিকা, সেক্ষেত্রে এটি কোনও ব্যবহারকারী-সংজ্ঞায়িত ফাংশন বা ম্যাক্রো।

    যদি fএআ স্ট্রিং হয়, অর্থাত্ একটি বিল্টিন ম্যাক্রো হয় তবে আমরা এটি যথাস্থানে পরিচালনা করি। যদি এটি ম্যাক্রো হয় iবা হয় তবে vআমরা এর প্রথম অপারেন্ডকে মূল্যায়ন করব এবং সে অনুযায়ী দ্বিতীয় বা তৃতীয় অপারেন্ড নির্বাচন করব i, বা ক্ষেত্রে প্রথম অপারেন্ডের ফলাফলটি ব্যবহার করব v; নির্বাচিত প্রকাশকে পুনরাবৃত্তির সাথে মূল্যায়ন করার পরিবর্তে, যা টিসিওকে পরাস্ত করবে, আমরা কেবলমাত্র প্রকাশিত বাক্যটি প্রতিস্থাপন করব eএবং লুপের শুরুতে ঝাঁপিয়ে দেব। যদি fম্যাক্রো হয় তবে dআমরা একটি জুড়ি সংযোজন করি, যার প্রথম উপাদানটি প্রথম অপারেন্ড, এবং যার দ্বিতীয় উপাদানটি দ্বিতীয় অপারেন্ডকে মূল্যায়ন করার ফলে, বিশ্বব্যাপী G, এবং প্রথম অপারেন্ডকে ফিরিয়ে দেয়। অন্যথায়, fম্যাক্রো q, এক্ষেত্রে আমরা কেবল তার অপারেন্ডটি প্রত্যক্ষভাবে ফিরিয়ে দিই।

    Othrtwise, যদি fএকটি ল্যাম্বডা হয়, বা একটি তালিকা যার প্রথম উপাদানটি নয় (), তবে এটি একটি অ-নালারি ফাংশন নয়, ম্যাক্রো নয়, সেক্ষেত্রে আমরা এর যুক্তিগুলি, অর্থাৎ, এর উপাদানগুলি মূল্যায়ন করি Aএবং Aফলাফলটি প্রতিস্থাপন করি ।

    যদি fল্যাম্বদা হয় তবে আমরা এটিকে কল করি, এটিতে আনপ্যাকড আর্গুমেন্টগুলি পাস করে A, এবং ফলাফলটি ফিরে আসি।

    অন্যথায়, fএকটি তালিকা, যেমন একটি ব্যবহারকারী-সংজ্ঞায়িত ফাংশন বা ম্যাক্রো; এর প্যারামিটারের তালিকাটি দ্বিতীয় থেকে শেষ উপাদান এবং এর শরীরটি সর্বশেষ উপাদান। ম্যাক্রোগুলির ক্ষেত্রে iএবং vটিসিও সম্পাদনের জন্য, আমরা শরীরকে পুনরাবৃত্তির সাথে মূল্যায়ন করি না, বরং eদেহের সাথে প্রতিস্থাপন করি এবং পরবর্তী পুনরাবৃত্তির দিকে চালিয়ে যাই । এর বিপরীতে iএবং vতবে আমরা Lফাংশনের নতুন স্থানীয় সুযোগের সাথে স্থানীয় স্কোপটিও প্রতিস্থাপন করি । যদি প্যারামিটারের তালিকাটি, Pআসলে, একটি তালিকা Pহয় তবে আর্গুমেন্ট তালিকার সাথে প্যারামিটার তালিকাটি জিপ করে নতুন স্থানীয় সুযোগ তৈরি করা হয় A; অন্যথায়, আমরা একটি বৈকল্পিক ফাংশন নিয়ে কাজ করছি, সেক্ষেত্রে নতুন স্থানীয় স্কোপটিতে কেবল একটি উপাদান রয়েছে, জোড় (P, A)

REPL

আপনি যদি এটির সাথে খেলতে চান তবে এখানে দোভাষীর একটি REPL সংস্করণ। এটি প্রতীককে নতুন করে সংজ্ঞায়িত করতে এবং কমান্ড লাইন আর্গুমেন্ট বা (import <filename>)ম্যাক্রোর মাধ্যমে ফাইল আমদানি সমর্থন করে । দোভাষী থেকে প্রস্থান করতে, ইনপুটটি বন্ধ করুন (সাধারণত, Ctrl + D বা Ctrl + Z)।

এবং এখানে উদাহরণস্বরূপ একটি অধিবেশন, মার্জ সাজানোর প্রয়োগ করা:


আপনি zlib ব্যবহার করে আরও ছোট কিছু পেতে পারেন :) আপনার কোডটি বাইটে রূপান্তরিত করুন এবং এটি দিয়ে প্রতিস্থাপন করুন:import zlib;exec(zlib.decompress(your_code_compressed_in_bytes))
Labo

A[0]ব্লক বাদে কিছুটা ওয়ান-চর চলক বরাদ্দ করে আপনি দুটি বাইট সংরক্ষণ করতে পারেন
হ্যানস কার্পিলা

@ হান্নেস কার্পপিলা এটি ঠিক, তবে এটি নালারী কার্যগুলি ভেঙে ফেলবে (যেহেতু Aএই ক্ষেত্রে খালি), এবং আমি "পুনরায়" চাপতে চাই না।
এলো

4

সি (জিএনইউ), 1095 বাইট

কর্মের বেশিরভাগ অংশটি জায়ান্ট vফাংশনে ঘটে । স্পষ্টভাবে লেজ পুনরাবৃত্তির বাস্তবায়ন করার পরিবর্তে, vতাই থেকে কল যে অনেক গঠিত হয় vথেকে vজিসিসি এর লেজ পুনরাবৃত্তির অপ্টিমাইজেশান দ্বারা পরিচালিত হবে। কোনও আবর্জনা সংগ্রহ নেই।

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

#define O(...)({o*_=malloc(32);*_=(o){__VA_ARGS__};_;})
#define P printf
#define F(I,B)({for(I;x->c;x=x->l)B;})
#define Z return
typedef struct o{struct o*n,*l,*c;int i,t;}o;E(o a,o b){Z
a.n?!strcmp(a.n,b.n):a.c?b.c&&E(*a.c,*b.c)&E(*a.l,*b.l):!b.c&a.i==b.i;}p(o*x){x->t?P("%d ",x->i):x->n?P("%s ",x->n):F(P("("),p(x->c);P(")"));}o*x,G,N;*C(o*h,o*t){Z
O(c:h,l:t);}o*v(o*x,o*e){o*W(o*l,o*e){Z
l->c?C(v(l->c,e),W(l->l,e)):&N;}o*y,*a,*f;int t;Z
x->c?y=v(x->c,e),x=x->l,t=y->i,t?9/t?a=v(x->c,e),t>7?(t>8?a->c:a->l)?:a:t>6?v(a,e):t<6?x=v(x->l->c,e),t>4?C(a,x):O(t:1,i:t>3?E(*a,*x):t>2?a->i<x->i:a->i-x->i):v((a-&N&&!a->t|a->i?x:x->l)->l->c,e):(t&1&&d(x->c->n,v(x->l->c,e)),x->c):(y->l->l->l?y=y->l:(x=W(x,e)),a=y->c,v(y->l->c,a->n?O(n:a->n,c:x,l:&G):F(f=&G,(f=O(n:a->c->n,c:x->c,l:f),a=a->l);f))):x->n?e->n?strcmp(x->n,e->n)?v(x,e->l):e->c:e:x;}d(o*n,o*x){*v(O(n:""),&G)=(o){n:n,c:x,l:O()};}*R(h){char*z,*q;Z
scanf(" %m[^ \n()]",&q)>0?h=strtoul(q,&z,10),C(*z?O(n:q):O(t:1,i:h),R()):~getchar()&1?q=R(),C(q,R()):&N;}main(i){for(;++i<12;)d(strndup("slecivthqd"+i-2,1),O(i:i));F(x=R(),p(v(x->c,&G)));}

সেমি-ungolfed

typedef struct o o;
struct o {
    char* n;
    o* l, //next in this list
     * c; 
    int i,
        t;
} ;



#define O(...)({o*_=malloc(32);*_=(o){__VA_ARGS__};_;})

E(o a, o b) { //tests equality 
    return
        a.n ? !strcmp(a.n,b.n) :
        a.t ? a.i==b.i :
        a.c ? b.c && E(*a.c,*b.c)&E(*a.l,*b.l) :
        !b.c
    ;
}

#define P printf


p(o*x){
    x->t?P("%d ",x->i):x->n?P("%s ",x->n):({for(P("(");x->c;x=x->l)p(x->c);P(")");});
}


o*_,G,N; //N = nil



o*C(o*h,o*t){return O(c:h,l:t);}


/*
        2 3 4 5 6 7 8 9 10 11
        s l e c i v t h d  q
    */


o* v(o* x, o* e) { //takes list, int, or name
    o*W(o* l, o* e) { //eval each item in list
        return l->c ? C(v(l->c ,e), W(l->l, e)) : &N;
    }

    o*y,*a,*f;int t;
    return x->c ? //nonempty list = function/macro call
        y = v(x->c,e), //evals to function/macro
        x = x->l,   //list position of first arg (if it exists)
        (t=y->t)?   //builtin no., if any
             t>9 ?
              t&1 ? x->c // 11 = q
                : //10 = d
                (d(x->c,v(x->l->c,e)),x->c)
           : (a = v(x->c,e), //eval'd first arg
             t)>7 ? // t/h
                (t > 8 ? a->c : a->l) ?: a
           : t>6 ? //v
                v(a,e)
           : (x = x->l, //position of 2nd arg in list
             t)>5 ? //i
                v( (a->n||a->l||a->i|a->t>1 ? x : x->l)->c, e)
           : (x = v(x->c,e), //evaluated 2nd arg
             t)>4 ? // c
                C(a,x)
           : O(t:1,i:
                t>3 ? E(*a,*x) :  //e
                t>2 ? a->i<x->i : //l
                      a->i-x->i   //s
              )
        :
        (
            y->l->l->l ? //whether this is macro
                y = y->l :
                (x = W(x,e)),  //eval args
            a = y->c,  //a = arg list
            //a = a->n ? x=C(x, &N), C(a, &N) : a, //transform variadic style to normal
            v(y->l->c,
               a->n ? //variadic
                O(n:a->n,c:x,l:&G)
              : ({
                   for(f=&G; a->c; a=a->l,x=x->l)
                      f=O(n:a->c->n, c: x->c, l:f);
                   f;
                })
            )
        )
    :
    x->n ? // name
        e->n ?
            strcmp(x->n,e->n) ?
                v(x,e->l)
            : e->c
        : e
     : x; //int or nil
}

d(o*n,o*x){
    * v(O(n:""),&G) =
        (o){n:n->n,c:x,l:O()};
}


;
o*R(){
    char*z,*q;int h;
return scanf(" %m[^ \n()]",&q)>0?
    h=strtoul(q,&z,10),
    C(*z ? O(n:q) : O(t:1,i:h), R())
: getchar()&1?&N:(q=R(),C(q,R()));
}
main(i) {

    for(;++i<12;) d(O(n:strndup("slecivthdq"+i-2,1)),O(t:i));

    o *q;
    for(q=R(); q->c; q=q->l) p(v(q->c,&G));

}

সংকলিত নির্বাহের ব্যবহার কী? এটা কি REPL? এটি কি ইনপুট হিসাবে কোনও ফাইলের নাম নেয়?
ckjbgames

@ckjbgames এটি স্টাডিনের একটি প্রোগ্রাম পড়ে।
feersum

ঠিক আছে. আমি মনে করি আপনার উত্তরটি সম্পাদনা করা উচিত এবং এটি নোট করুন।
ckjbgames

1

সিলোন, 2422 বাইট

(আমি মনে করি এটি এখনও আমার দীর্ঘতম গল্ফযুক্ত প্রোগ্রাম))

import ceylon.language{sh=shared,va=variable,fo=formal,O=Object}import ceylon.language.meta.model{F=Function}interface X{sh fo V v(S t);sh fo G g;}class G(va Map<S,V>m)satisfies X{v(S t)=>m[t]else nV;g=>this;sh S d(S s,V v){assert(!s in m);m=map{s->v,*m};return s;}}V nV=>nothing;class LC(G c,Map<S,V>m)satisfies X{g=>c;v(S t)=>m[t]else g.v(t);}alias C=>V|Co;interface Co{sh fo C st();}interface V{sh fo C l(X c,V[]a);sh default Boolean b=>0<1;sh fo C vO(X c);sh default V vF(X c){va C v=vO(c);while(is Co n=v){v=n.st();}assert(is V r=v);return r;}}class L(sh V*i)satisfies V{vO(X c)=>if(nonempty i)then i[0].vF(c).l(c,i.rest)else this;equals(O o)=>if(is L o)then i==o.i else 1<0;b=>!i.empty;string=>"(``" ".join(i)``)";hash=>i.hash;sh actual C l(X c,V[]p){value[h,ns,x]=i.size<3then[f,i[0],i[1]]else[m,i[1],i[2]];value n=if(is L ns)then[*ns.i.narrow<S>()]else ns;assert(is S|S[]n,is V x);V[]a=h(c,p);LC lC=if(is S n)then LC(c.g,map{n->L(*a)})else LC(c.g,map(zipEntries(n,a)));return object satisfies Co{st()=>x.vO(lC);};}}class S(String n)satisfies V{vO(X c)=>c.v(this);l(X c,V[]a)=>nV;equals(O o)=>if(is S o)then n==o.n else 1<0;hash=>n.hash;string=>n;}class I(sh Integer i)satisfies V{vO(X c)=>this;l(X c,V[]a)=>nV;equals(O o)=>if(is I o)then i==o.i else 1<0;hash=>i;b=>!i.zero;string=>i.string;}V[]f(X c,V[]a)=>[for(v in a)v.vF(c)];V[]m(X c,V[]a)=>a;L c(X c,V h,L t)=>L(h,*t.i);V h(X c,L l)=>l.i[0]else L();V t(X c,L l)=>L(*l.i.rest);I s(X c,I f,I s)=>I(f.i-s.i);I l(X c,I f,I s)=>I(f.i<s.i then 1else 0);I e(X c,V v1,V v2)=>I(v1==v2then 1else 0);C v(X c,V v)=>v.vO(c);V q(X c,V a)=>a;C i(X c,V d,V t,V f)=>d.vF(c).b then t.vO(c)else f.vO(c);S d(X c,S s,V x)=>c.g.d(s,x.vF(c));class B<A>(F<C,A>nat,V[](X,V[])h=f)satisfies V given A satisfies[X,V+]{vO(X c)=>nV;string=>nat.declaration.name;l(X c,V[]a)=>nat.apply(c,*h(c,a));}{<S->V>*}b=>{S("c")->B(`c`),S("h")->B(`h`),S("t")->B(`t`),S("s")->B(`s`),S("l")->B(`l`),S("e")->B(`e`),S("v")->B(`v`),S("q")->B(`q`,m),S("i")->B(`i`,m),S("d")->B(`d`,m)};[V*]p(String inp){value ts=inp.split(" \n()".contains,1<0,1<0);va[[V*]*]s=[];va[V*]l=[];for(t in ts){if(t in" \n"){}else if(t=="("){s=[l,*s];l=[];}else if(t==")"){l=[L(*l.reversed),*(s[0]else[])];s=s.rest;}else if(exists i=parseInteger(t),i>=0){l=[I(i),*l];}else{l=[S(t),*l];}}return l.reversed;}sh void run(){va value u="";while(exists l=process.readLine()){u=u+l+"\n";}V[]e=p(u);X c=G(map(b));for(v in e){print(v.vF(c));}}

আমি কিছু জায়গায় আরও কিছু বাইট গল্ফ করতে পারতাম, কারণ আমি কিছু জায়গায় দুটি-অক্ষর শনাক্তকারী ব্যবহার করেছি, তবে আমি সেগুলির জন্য কিছুটা অর্থবহ একক অক্ষর ছাপিয়েছি। যদিও এইভাবে এটি সিলোন খুব ভাল লাগে না ...

এটি একটি অবজেক্ট ভিত্তিক বাস্তবায়ন।

আমাদের Vপ্রয়োগকারী ক্লাসগুলির Lএকটি তালিকা রয়েছে (তালিকা - একটি সিলোন ক্রমানুসারে কেবল একটি মোড়ক V), S(প্রতীক - একটি স্ট্রিংয়ের চারপাশে মোড়ক), I(পূর্ণসংখ্যা - একটি সিলন পূর্ণসংখ্যার চারপাশে মোড়ক) এবং B(বিল্টিন ফাংশন বা ম্যাক্রো, একটি প্রায় একটি রেভার ) সিলোন ফাংশন)।

আমি equalsপদ্ধতিটি প্রয়োগ করে (এবং hashবৈশিষ্ট্যটিও, যা সত্যই কেবল প্রতীকগুলির জন্য প্রয়োজন) এবং stringআউটপুট জন্য মানক বৈশিষ্ট্য প্রয়োগ করে আমি স্ট্যান্ডার্ড সিলোন সমতা স্বীকৃতি ব্যবহার করি।

আমরা একটি বুলিয়ান অ্যাট্রিবিউট আছে b(যা ডিফল্ট, ওভাররাইড করা দ্বারা সত্য Iএবং Lখালি তালিকা বিনিময়ে মিথ্যাতে), এবং দুটি পদ্ধতি l(কল, অর্থাত একটি ফাংশন হিসাবে এই বস্তুর ব্যবহার করুন) এবং vO(এক ধাপ নির্ণয়)। উভয়ই মান বা একটি ধারাবাহিক অবজেক্ট প্রত্যাবর্তন করে যা আরও একটি পদক্ষেপের জন্য মূল্যায়ন করতে দেয় এবং vFফলাফলটির ধারাবাহিকতা না হওয়া পর্যন্ত (পুরোপুরি মূল্যায়ন) লুপগুলি সরবরাহ করে।

একটি প্রসঙ্গ ইন্টারফেস চলকগুলিতে অ্যাক্সেসের অনুমতি দেয়। দুটি বাস্তবায়ন রয়েছে, Gবৈশ্বিক প্রেক্ষাপটের জন্য (যা dবিল্টিন ব্যবহার করে ভেরিয়েবল যুক্ত করার অনুমতি দেয় ) এবং LCস্থানীয় প্রসঙ্গের জন্য, যা ব্যবহারকারীর ফাংশনের অভিব্যক্তি মূল্যায়নের সময় সক্রিয় থাকে (এটি বিশ্বব্যাপী প্রসঙ্গে ফিরে আসে)।

প্রতীকগুলির মূল্যায়ন প্রসঙ্গে অ্যাক্সেস করে, তালিকাগুলি (খালি না হলে) প্রথমে তাদের প্রথম উপাদানটির মূল্যায়ন করে তার কল পদ্ধতিতে কল করে ate কলটি কেবলমাত্র তালিকা এবং বিল্টিনগুলির দ্বারা প্রয়োগ করা হয় - এটি প্রথমে আর্গুমেন্টের মূল্যায়ন করে (যদি কোনও ফাংশন না হয় তবে ম্যাক্রো হয়) এবং তারপরে প্রকৃত আকর্ষণীয় জিনিসগুলি তৈরি করে - বিল্টিনদের জন্য যা হার্ডকোডযুক্ত, তালিকাগুলির জন্য এটি একটি নতুন স্থানীয় প্রসঙ্গ তৈরি করে এবং ফিরে আসে যে ধারাবাহিকতা।

বিল্টিনগুলির জন্য আমি আমার শিফট ইন্টারপ্রেটারে যেমন ব্যবহার করেছি তার অনুরূপ একটি কৌশল ব্যবহার করেছি , যা আমাকে তাদের প্রয়োজনীয় যুক্তি প্রকারের সাথে সংজ্ঞায়িত করতে দেয়, তবে প্রতিচ্ছবি ব্যবহার করে জেনেরিক ক্রম দিয়ে তাদের কল করে (প্রকারগুলি কল সময়ে পরীক্ষা করা হবে)। এটি ফাংশন / ম্যাক্রোগুলির অভ্যন্তরে ধরণের রূপান্তর / দৃser় ঝামেলা এড়ায়, তবে শীর্ষ স্তরের ফাংশন প্রয়োজন যাতে আমি তাদের মেটা-মডেল Functionঅবজেক্টগুলি পেতে পারি ।

p(পার্স) ফাংশন স্পেস, নতুন লাইন এবং বন্ধনী এ স্ট্রিং splits, তারপর টোকেন উপর loops এবং একটি স্ট্যাক এবং একটি চলমান তালিকাটি ব্যবহার করে তালিকা তৈরী করে।

দোভাষী ( runপদ্ধতিতে, যা প্রবেশের বিন্দুতে থাকে) তারপরে এই অভিব্যক্তিগুলির তালিকাটি (যা কেবলমাত্র মূল্যবোধক) নিয়ে যায়, সেগুলির প্রতিটিকে মূল্যায়ন করে এবং ফলাফলটি মুদ্রণ করে।


নীচে মন্তব্য সহ একটি সংস্করণ রয়েছে এবং একটি ফর্ম্যাটারের মাধ্যমে চালানো হয়।

আমি গল্ফিং শুরু করার আগে একটি পূর্ববর্তী সংস্করণ (এবং এখনও তালিকার মূল্যায়নের বিষয়ে কিছু ভুল বোঝাবুঝি সহ) আমার গিথুব সংগ্রহশালায় পাওয়া গেছে , আমি খুব শীঘ্রই এটিকে সেখানে রাখব (সুতরাং যদি আপনি আসলটি চান তবে প্রথম সংস্করণটি দেখুন )।

//  Tiny Lisp, tiny interpreter
//
// An interpreter for a tiny subset of Lisp, from which most of the
// rest of the language can be bootstrapped.
//
// Question:   https://codegolf.stackexchange.com/q/62886/2338
// My answer:  https://codegolf.stackexchange.com/a/63352/2338
//
import ceylon.language {
    sh=shared,
    va=variable,
    fo=formal,
    O=Object
}
import ceylon.language.meta.model {
    F=Function
}

// context

interface X {
    sh fo V v(S t);
    sh fo G g;
}
// global (mutable) context, with the buildins 
class G(va Map<S,V> m) satisfies X {
    // get entry throws error on undefined variables. 
    v(S t) => m[t] else nV;
    g => this;
    sh S d(S s, V v) {
        // error when already defined
        assert (!s in m);
        // building a new map is cheaper (code-golf wise) than having a mutable one.
        m = map { s->v, *m };
        return s;
    }
}

// This is simply a shorter way of writing "this is not an allowed operation".
// It will throw an exception when trying to access it.
// nV stands for "no value".
V nV => nothing;

// local context
class LC(G c, Map<S,V> m) satisfies X {
    g => c;
    v(S t) => m[t] else g.v(t);
    // sh actual String string => "[local: ``m``, global: ``g``]";
}

// continuation or value
alias C => V|Co;

// continuation
interface Co {
    sh fo C st();
}

// value
interface V {
    // use this as a function and call with arguments.
    // will not work for all types of stuff.
    sh fo C l(X c, V[] a);
    // check the truthiness. Defaults to true, as
    // only lists and integers can be falsy.
    sh default Boolean b => 0 < 1;
    // evaluate once (return either a value or a continuation).
    // will not work for all kinds of expression.
    sh fo C vO(X c);
    /// evaluate fully
    sh default V vF(X c) {
        va C v = vO(c);
        while (is Co n = v) {
            v = n.st();
        }
        assert (is V r = v);
        return r;
    }
}
class L(sh V* i) satisfies V {

    vO(X c) => if (nonempty i) then i[0].vF(c).l(c, i.rest) else this;
    equals(O o) => if (is L o) then i == o.i else 1 < 0;
    b => !i.empty;
    string => "(``" ".join(i)``)";
    hash => i.hash;

    sh actual C l(X c, V[] p) {
        value [h, ns, x] =
                i.size < 3
                then [f, i[0], i[1]]
                else [m, i[1], i[2]];
        // parameter names – either a single symbol, or a list of symbols.
        // If it is a list, we filter it to throw out any non-symbols.
        // Should throw an error if there are any, but this is harder.
        value n = if (is L ns) then [*ns.i.narrow<S>()] else ns;
        assert (is S|S[] n, is V x);
        V[] a = h(c, p);

        // local context
        LC lC = if (is S n) then
            LC(c.g, map { n -> L(*a) })
        else
            LC(c.g, map(zipEntries(n, a)));
        // return a continuation instead of actually
        // calling it here, to allow stack unwinding.
        return object satisfies Co {
            st() => x.vO(lC);
        };
    }
}

// symbol
class S(String n) satisfies V {
    // evaluate: resolve
    vO(X c) => c.v(this);
    // call is not allowed
    l(X c, V[] a) => nV;
    // equal if name is equal
    equals(O o) => if (is S o) then n == o.n else 1 < 0;
    hash => n.hash;
    string => n;
}

// integer
class I(sh Integer i) satisfies V {

    vO(X c) => this;
    l(X c, V[] a) => nV;
    equals(O o) => if (is I o) then i == o.i else 1 < 0;
    hash => i;
    b => !i.zero;
    string => i.string;
}

// argument handlers for functions or macros
V[] f(X c, V[] a) => [for (v in a) v.vF(c)];
V[] m(X c, V[] a) => a;

// build-in functions
// construct
L c(X c, V h, L t) => L(h, *t.i);
// head
V h(X c, L l) => l.i[0] else L();
// tail
V t(X c, L l) => L(*l.i.rest);
// subtract
I s(X c, I f, I s) => I(f.i - s.i);
// lessThan
I l(X c, I f, I s) => I(f.i < s.i then 1 else 0);
// equal
I e(X c, V v1, V v2) => I(v1 == v2 then 1 else 0);
// eval (returns potentially a continuation)
C v(X c, V v) => v.vO(c);

// build-in macros
// quote
V q(X c, V a) => a;
// if (also returns potentially a continuation)
C i(X c, V d, V t, V f) => d.vF(c).b then t.vO(c) else f.vO(c);
// define symbol in global context
S d(X c, S s, V x) => c.g.d(s, x.vF(c));

// buildin function or macro, made from a native function and an argument handler
class B<A>(F<C,A> nat, V[](X, V[]) h = f)
        satisfies V
        given A satisfies [X, V+] {
    vO(X c) => nV;
    string => nat.declaration.name;
    // this "apply" is a hack which breaks type safety ...
    // but it will be checked at runtime.
    l(X c, V[] a) => nat.apply(c, *h(c, a));
}

// define buildins
{<S->V>*} b => {
    S("c") -> B(`c`),
    S("h") -> B(`h`),
    S("t") -> B(`t`),
    S("s") -> B(`s`),
    S("l") -> B(`l`),
    S("e") -> B(`e`),
    S("v") -> B(`v`),
    S("q") -> B(`q`, m),
    S("i") -> B(`i`, m),
    S("d") -> B(`d`, m)
};

// parses a string into a list of expressions.
[V*] p(String inp) {
    // split string into tokens (retain separators, don't group them –
    // whitespace and empty strings will be sorted out later in the loop)
    value ts = inp.split(" \n()".contains, 1 < 0, 1 < 0);
    // stack of not yet finished nested lists, outer most at bottom
    va [[V*]*] s = [];
    // current list, in reverse order (because appending at the start is shorter)
    va [V*] l = [];
    for (t in ts) {
        if (t in " \n") {
            // do nothing for empty tokens
        } else if (t == "(") {
            // push the current list onto the stack, open a new list.
            s = [l, *s];
            l = [];
        } else if (t == ")") {
            // build a lisp list from the current list,
            // pop the latest list from the stack, append the created lisp list. 
            l = [L(*l.reversed), *(s[0] else [])];
            s = s.rest;
        } else if (exists i = parseInteger(t), i >= 0) {
            // append an integer to the current list.
            l = [I(i), *l];
        } else {
            // append a symbol to the current list.
            l = [S(t), *l];
        }
    }
    return l.reversed;
}

// Runs the interpreter.
// This handles input and output, calls the parser and evaluates the expressions.
sh void run() {
    va value u = "";
    while (exists l = process.readLine()) {
        u = u + l + "\n";
    }
    V[] e = p(u);
    // create global context
    X c = G(map(b));
    // iterate over the expressions, ...
    for (v in e) {
        // print("  '``v``' → ...");
        // ... evaluate each (fully) and print the result.
        print(v.vF(c));
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.