পরিবর্তনীয় ভেরিয়েবল ব্যবহার না করে কীভাবে দরকারী জাভা প্রোগ্রাম লিখতে হয়


12

আমি ফাংশনাল প্রোগ্রামিং সম্পর্কে একটি নিবন্ধ পড়ছিলাম যেখানে লেখক বলেছেন

(take 25 (squares-of (integers)))

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

জাভাতে এটি অর্জন করা সম্ভব? ধরুন আপনার প্রথম 15 পূর্ণসংখ্যার স্কোয়ার মুদ্রণ করা দরকার, আপনি ভেরিয়েবলগুলি ব্যবহার না করে লুপের জন্য লিখতে পারেন নাকি?

মোড নোটিশ

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


19
আপনার কার্যকরী উদাহরণটি অভ্যন্তরে ভেরিয়েবল ব্যবহার করে , তবে ভাষা পর্দার আড়ালে সমস্ত কিছু করে। আপনি যদি বিশ্বাস করেন যে কেউ এটি বিশ্বাসযোগ্যভাবে কার্যকরভাবে কার্যকর করেছেন তখন আপনি অপ্রীতিকর অংশগুলি কার্যকরভাবে অর্পণ করেছেন।
blrfl

12
@ ব্লারফ্লাল: "পর্দার অন্তরালে" যুক্তিটি সমস্ত ভাষাভিত্তিক বিতর্ককে হত্যা করে, যেহেতু কোডের প্রতিটি অংশ শেষ পর্যন্ত x86 মেশিন কোডে অনুবাদ করা হয়। x86 কোড বস্তু-ভিত্তিক নয়, পদ্ধতিগত নয়, কার্যকরী নয়, কিছুই নয়, তবে এই বিভাগগুলি প্রোগ্রামিং ভাষার জন্য মূল্যবান ট্যাগ। ভাষাটি দেখুন, বাস্তবায়ন নয়।
thiton

10
@ থাইটন অসম্মতি ব্লারফ্লিল যা বলছে তা হ'ল এই ফাংশনগুলি সম্ভবত একই প্রোগ্রামিং ভাষায় লেখা ভেরিয়েবলগুলি ব্যবহার করে । এখানে নিম্ন-স্তরের যাওয়ার দরকার নেই। স্নিপেট কেবল গ্রন্থাগারের ফাংশন ব্যবহার করছে। আপনি জাভাতে একই কোডটি সহজেই লিখতে পারেন, দেখুন: squaresOf(integers()).take(25)(এই ফাংশনগুলি লেখার জন্য পাঠকের অনুশীলন হিসাবে ছেড়ে দেওয়া হয়েছে; অসুবিধাটি অসীম সেটে রয়েছে তবে জাভাটির জন্য integers()এটি একটি সমস্যা কারণ এর উদগ্রীব মূল্যায়নের কারণে কিছুই করার নেই) পরিবর্তনশীল)
Andres F.

6
এই উক্তিটি বিভ্রান্তিকর এবং বিভ্রান্তিমূলক, সেখানে কোনও জাদু নেই, কেবল সিনট্যাকটিক চিনি
ইয়ানিস

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

উত্তর:


31

জাভাতে ধ্বংসাত্মক আপডেট ব্যবহার না করেই কি এই জাতীয় উদাহরণ প্রয়োগ করা সম্ভব? হ্যাঁ. যাইহোক, @ থাইটন এবং নিজেই নিবন্ধটি উল্লিখিত হিসাবে এটি কুরুচিপূর্ণ হবে (কারও স্বাদের উপর নির্ভর করে)। একটি উপায় পুনরাবৃত্তি ব্যবহার করা হয়; এখানে একটি হাস্কেলের উদাহরণ যা একই রকম কিছু করে:

unfoldr      :: (b -> Maybe (a, b)) -> b -> [a]
unfoldr f b  =
  case f b of
   Just (a,new_b) -> a : unfoldr f new_b
   Nothing        -> []  

দ্রষ্টব্য 1) রূপান্তরকরণের অভাব, ২) পুনরাবৃত্তি ব্যবহার এবং 3) লুপের অভাব। শেষ পয়েন্টটি অত্যন্ত গুরুত্বপূর্ণ - কার্যকরী ভাষাগুলিতে ভাষায় অন্তর্নির্মিত লুপিং কনস্ট্রাক্টসের প্রয়োজন নেই, যেহেতু পুনরাবৃত্তি বেশিরভাগ (সমস্ত?) ক্ষেত্রে জাভাতে লুপগুলি ব্যবহৃত হয় সে ক্ষেত্রে ব্যবহার করা যেতে পারে। অবিশ্বাস্যভাবে এক্সপ্রেসিভ ফাংশন কলগুলি কী হতে পারে তা দেখানোর জন্য এখানে একটি সুপরিচিত কাগজপত্র রয়েছে।


আমি নিবন্ধটি অসন্তুষ্টিজনক পেয়েছি এবং কয়েকটি অতিরিক্ত পয়েন্ট তৈরি করতে চাই:

এই নিবন্ধটি কার্যকরী প্রোগ্রামিং এবং এর সুবিধাগুলির একটি খুব দুর্বল এবং বিভ্রান্তিকর ব্যাখ্যা। ফাংশনাল প্রোগ্রামিং সম্পর্কে শেখার জন্য আমি অন্যান্য উত্সকে দৃ strongly়ভাবে সুপারিশ করব ।

নিবন্ধটি সম্পর্কে সবচেয়ে বিভ্রান্তিকর অংশটি এটি জাভাতে অ্যাসাইনমেন্ট স্টেটমেন্টের জন্য দুটি ব্যবহার রয়েছে (এবং বেশিরভাগ মূলধারার অন্যান্য ভাষাগুলি) উল্লেখ করে না:

  1. একটি নামের সাথে একটি মান আবদ্ধ করা: final int MAX_SIZE = 100;

  2. ধ্বংসাত্মক আপডেট: int a = 3; a += 1; a++;

ক্রিয়ামূলক প্রোগ্রামিং দ্বিতীয়টি প্রতিরোধ করে, তবে প্রথমটিকে আলিঙ্গন করে ( letউদাহরণস্বরূপ : এক্সপ্রেসনস, ফাংশন প্যারামিটারগুলি, শীর্ষ স্তরের defineআইটিওনস) । কারণ অন্যথায় নিবন্ধ মাত্র নিরীহ মনে হয় এবং আপনি হতাশ ছেড়ে পারে, কি এই উপলব্ধি করতে একটি খুব গুরুত্বপূর্ণ পয়েন্ট take, squares-ofএবং integersযদি না ভেরিয়েবল?

এ ছাড়া উদাহরণটি অর্থহীন। এটা বাস্তবায়নের প্রদর্শন করা হয় না take, squares-ofঅথবা integers। আমরা জানি সকলের জন্য এগুলি পরিবর্তনীয় ভেরিয়েবলগুলি ব্যবহার করে প্রয়োগ করা হয়। @ মার্টিন যেমন বলেছিলেন, আপনি জাভাতে এই উদাহরণটি তুচ্ছভাবে লিখতে পারেন।

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

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

[...]

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


10
+1 এর জন্য "আমি এই নিবন্ধটি এবং এটিকে অন্যদের মতো করে এড়িয়ে চলার পরামর্শ দিচ্ছি যদি আপনি সত্যিকার অর্থেই ফাংশনাল প্রোগ্রামিং সম্পর্কে শিখতে চান। ধারণা এবং মৌলিক বিষয়গুলি শেখানোর চেয়ে শকিং এবং আপত্তিকর লক্ষ্য নিয়ে এটি আরও লেখা হয়েছে বলে মনে হয়।"

3
লোকেরা এফপি না করার অর্ধ কারণ হ'ল তারা ইউনিতে এ সম্পর্কে কিছুই শুনেন না / শিখেন না এবং অন্য অর্ধেকটি কারণ তারা এগুলি দেখলে তারা এমন নিবন্ধগুলি আবিষ্কার করেন যা তাদের উভয়কেই অজ্ঞাত করে ফেলেছিল এবং চিন্তা করে যে এটি কিছু কল্পিতের জন্য রয়েছে সুবিধাগুলি নিয়ে চিন্তার বাইরে যুক্তিযুক্ত হওয়ার চেয়ে বাজানো। তথ্যের আরও উত্স দেওয়ার জন্য +1
জিমি হোফা

3
আপনার প্রশ্নের উত্তরটি একেবারে শীর্ষে রাখুন আপনি যদি তাই করেন তবে এটি প্রশ্নের দিকে আরও সরাসরি এবং সম্ভবত এই প্রশ্নটি তখন খোলা থাকবে (সরাসরি প্রশ্ন-কেন্দ্রিক উত্তর সহ)
জিমি হোফা

2
নিতপিকের জন্য দুঃখিত, তবে আপনি কেন এই হ্যাশেল কোডটি বেছে নিয়েছেন তা আমি বুঝতে পারি না। আমি লায়াহ পড়েছি এবং আপনার উদাহরণটি আমার পক্ষে কুঁকড়ে ফেলা কঠিন। আমিও মূল প্রশ্নের সাথে সম্পর্ক দেখছি না। কেন আপনি শুধু take 25 (map (^2) [1..])উদাহরণ হিসাবে ব্যবহার করেন নি?
ড্যানিয়েল কাপলান

2
@ টিটিটিটি ভাল প্রশ্ন - এটি নির্দেশ করার জন্য ধন্যবাদ। আমি উদাহরণটি ব্যবহার করার কারণ এটি দেখায় যে পুনরাবৃত্তি ব্যবহার করে এবং পরিবর্তনীয় ভেরিয়েবলগুলি এড়ানো কীভাবে সংখ্যার একটি তালিকা তৈরি করা যায়। আমার উদ্দেশ্য ওপি'র সেই কোডটি দেখতে এবং জাভাতে কীভাবে অনুরূপ কিছু করা যায় তা চিন্তা করার জন্য ছিল। আপনার কোড স্নিপেট ঠিকানা, কি [1..]? এটি হাস্কেলের কাছে অন্তর্নির্মিত একটি দুর্দান্ত বৈশিষ্ট্য, তবে এই জাতীয় তালিকা উত্পন্ন করার পিছনে ধারণাগুলি চিত্রিত করে না। আমি নিশ্চিত যে Enumক্লাসের উদাহরণগুলি (যা সিনট্যাক্সের প্রয়োজন) এছাড়াও সহায়ক, তবে সেগুলি খুঁজে পাওয়া খুব অলস ছিল। এইভাবে unfoldr,। :)

27

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

সুতরাং, জাভা উপায়টি হ'ল:

for (int i = 1; i <= 25; ++i) {
    System.out.println(i*i);
}

এবং ভেরিয়েবলের বিদ্বেষের কারণে নিজেকে আর জটিল পদ্ধতিতে লিখতে বোকা বানাবেন না।


5
"ভেরিয়েবলের ঘৃণা"? ওওওকে ... ফাংশনাল প্রোগ্রামিং সম্পর্কে আপনি কী পড়েছেন? আপনি কোন ভাষায় চেষ্টা করেছেন? কোন টিউটোরিয়াল?
আন্দ্রেস এফ।

8
@ অ্যান্ড্রেসএফ: হাস্কেলের দুই বছরেরও বেশি কোর্সওয়ার্ক। আমি বলি না এফপি খারাপ। তবে অনেকগুলি এফপি-বনাম-আইপি আলোচনার (যেমন সংযুক্ত নিবন্ধ হিসাবে) পুনঃ-এসাইয়েবল নামধারী সত্তা (একেএ ভেরিয়েবল) ব্যবহারের নিন্দা করার এবং প্রযোজনীয় কারণ বা ডেটা ছাড়াই নিন্দার প্রবণতা রয়েছে। অযৌক্তিক নিন্দা করা আমার বইতে ঘৃণা। এবং ঘৃণা সত্যই খারাপ কোড তৈরি করে।
থাইটন

10
"ভেরিয়েবলের বিদ্বেষ" কার্যকারিতা ওভারসিম্প্লিকেশন en.wikedia.org/wiki/Fallacy_of_the_single_ কারন স্টেটলেস প্রোগ্রামিংয়ের অনেক সুবিধা রয়েছে যা জাভাতেও হতে পারে, যদিও আমি আপনার জবাবের সাথে সম্মত হই যে জাভাতে ব্যয় জটিলতায় খুব বেশি হবে প্রোগ্রাম এবং অ-অহঙ্কারী হচ্ছে। অভিজ্ঞতার কারণে মানুষ যুক্তিযুক্ত, সুচিন্তিত অবস্থানের পরিবর্তে কিছুটা আবেগপ্রবণ প্রতিক্রিয়া না দিয়ে রাষ্ট্রহীন প্রোগ্রামিং ভাল এবং রাষ্ট্রীয়ভাবে খারাপ বলে এই ধারণাটি আমি হাতছাড়া করতে পারি না।
জিমি হোফা

2
@ জিমিহোফা যা বলেছেন তার সাথে ইনলাইন করুন, আমি আপনাকে জরুরী ভাষাগুলিতে ফাংশনাল স্টাইল প্রোগ্রামিং (তার ক্ষেত্রে সি ++) প্রসঙ্গে জন কারম্যাকের কাছে উল্লেখ করব ( altdevblogaday.com/2012/04/26/functional-programming-in-c )।
স্টিভেন ইভার্স

5
অযৌক্তিক নিন্দা ঘৃণা নয়, এবং পরিবর্তনীয় অবস্থা এড়ানো অযৌক্তিক নয়।
মাইকেল শ

21

পুনরাবৃত্তির সাথে সবচেয়ে সহজ আমি যা করতে পারি তা হ'ল একটি পরামিতি সহ একটি ফাংশন। এটি খুব জাভা-এস্কো নয়, তবে এটি কাজ করে:

public class squares
{
    public static void main(String[] args)
    {
        squares(15);
    }

    private static void squares(int x)
    {
        if (x>0)
        {
            System.out.println(x*x);
            squares(x-1);
        }
    }
}

3
জাভা উদাহরণ দিয়ে প্রশ্নের উত্তর দেওয়ার চেষ্টা করার জন্য +1।
কেচালাক্স

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

3
@gnat: এই উত্তরটি Mod নোটিশের আগে পোস্ট করা হয়েছিল। আমি দুর্দান্ত স্টাইলে যাচ্ছিলাম না, আমি সরলতার জন্য যাচ্ছিলাম, এবং ওপির মূল প্রশ্নটি সন্তুষ্ট করছি; জাভাতে এই জাতীয় জিনিসগুলি করা সম্ভব কিনা তা বোঝাতে।
হতাশ

নিবন্ধন করুন এটি আমাকে ডিভিং করা থেকে বিরত রাখবে না (যেহেতু আপনি মেনে চলার জন্য সম্পাদনা করতে সক্ষম হবেন ) - এটি আকর্ষণীয়ভাবে নিখুঁত ম্যাচ যা ম্যাজিকটি করেছে। শাবাশ, সত্যিই ভাল কাজ করেছেন, মোটামুটি শিক্ষাপ্রদ - তোমাকে ধন্যবাদ
মশা

16

আপনার কার্যকরী উদাহরণে আমরা কীভাবে squares-ofএবং takeকার্যাদি কার্যকর করা হয় তা দেখতে পাই না । আমি জাভা বিশেষজ্ঞ নই, তবে আমি নিশ্চিত যে আমরা এই জাতীয় বিবৃতি সক্ষম করতে এই ফাংশনগুলি লিখতে পারি ...

squares_of(integers).take(25);

যা এতটা আলাদা নয়।


6
নিতপিক: squares-ofজাভাতে কোনও বৈধ নাম নয় ( squares_ofযদিও এটি)। তবে অন্যথায়, ভাল পয়েন্ট যা নিবন্ধের উদাহরণটি দরিদ্র তা দেখায়।

আমি সন্দেহ করি যে নিবন্ধটির integerআলস্যভাবে পূর্ণসংখ্যার উত্পন্ন হয় এবং takeফাংশনটি 25 টির squared-ofসংখ্যার তুলনা করে integer। সংক্ষেপে, আপনার integerঅনাহারে অলসভাবে পূর্ণসংখ্যার উত্পাদন করার জন্য একটি ফাংশন থাকা উচিত ।
ওনিসিমাসউবাউন্ড

(integer)কোনও ফাংশন এর মতো কিছু বলা কিছুটা উন্মাদনা - একটি ফাংশন এখনও এমন কিছু যা মানকে একটি যুক্তি মানচিত্র করে । দেখা যাচ্ছে যে (integer)এটি কোনও ফাংশন নয়, তবে কেবল একটি মান। কেউ এমনকি এতদূর যেতে পারে যে integerএটি একটি পরিবর্তনশীল যা সংখ্যার অসীম স্ট্রিমের সাথে আবদ্ধ।
ইনগো

6

জাভাতে আপনি এটির (যেমন অসীম তালিকার অংশ) পুনরাবৃত্তিকারীদের সাথে করতে পারেন। নিম্নলিখিত কোড নমুনায়, Takeকনস্ট্রাক্টর সরবরাহ করা নম্বর নির্বিচারে উচ্চ হতে পারে।

class Example {
    public static void main(String[] a) {
        Numbers test = new Take(25, new SquaresOf(new Integers()));
        while (test.hasNext())
            System.out.println(test.next());
    }
}

বা শৃঙ্খলযোগ্য কারখানার পদ্ধতি সহ:

class Example {
    public static void main(String[] a) {
        Numbers test = Numbers.integers().squares().take(23);
        while (test.hasNext())
            System.out.println(test.next());
    }
}

কোথায় SquaresOf, Takeএবং Integersপ্রসারিতNumbers

abstract class Numbers implements Iterator<Integer> {
    public static Numbers integers() {
        return new Integers();
    }

    public Numbers squares() {
        return new SquaresOf(this);
    }

    public Numbers take(int c) {
        return new Take(c, this);
    }
    public void remove() {}
}

1
এটি কার্যকরী একের চেয়ে ওও দৃষ্টান্তের শ্রেষ্ঠত্ব দেখায়; যথাযথ ওও ডিজাইনের সাহায্যে আপনি কার্যকরী দৃষ্টান্তের নকল করতে পারেন তবে কার্যকরী শৈলীতে আপনি ও ও দৃষ্টান্তকে অনুকরণ করতে পারবেন না।
m3th0dman

3
@ এম 3 তম ডিডম্যান: যথাযথ ওও ডিজাইনের সাহায্যে আপনি সম্ভবত অর্ধ-assedly এফপি অনুকরণ করতে পারেন , যেমন স্ট্রিং, তালিকাগুলি এবং / অথবা অভিধানগুলি অর্ধ-অ্যাসিডলি ওও অনুকরণ করতে পারে like সাধারণ-উদ্দেশ্যমূলক ভাষার টুরিং সমতুল্যর অর্থ হল যে যথেষ্ট পরিশ্রম করা হলে যে কোনও ভাষা অন্য যে কোনওটির বৈশিষ্ট্যগুলি অনুকরণ করতে পারে।
সিএওও

নোট করুন যে জাভা-স্টাইলের পুনরাবৃত্তিগুলি এফপিতে while (test.hasNext()) System.out.println(test.next())কোনও নং হবে; পুনরুক্তিকারী সহজাতভাবে পরিবর্তনযোগ্য।
সিএওও

1
@ সিএইচও আমি দৃly়ভাবে বিশ্বাস করি যে সত্য এনক্যাপসুলেশন বা পলিমারফিজম অনুকরণ করা যায়; এছাড়াও জাভা (এই উদাহরণস্বরূপ) কঠোর উত্সাহী মূল্যায়নের কারণে সত্যিকার অর্থে একটি কার্যকরী ভাষার অনুকরণ করতে পারে না। আমি আরও বিশ্বাস করি যে পুনরাবৃত্তকারীকে পুনরাবৃত্ত পদ্ধতিতে লেখা যেতে পারে।
m3th0dman

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

6

সংক্ষিপ্ত সংস্করণ:

জাভাতে একক-অ্যাসাইনমেন্ট শৈলীর নির্ভরযোগ্যতার সাথে কাজ করার জন্য আপনার (1) কিছু প্রকারের অপরিবর্তনীয়-বন্ধুত্বপূর্ণ অবকাঠামো এবং (2) সংকলক- বা টেল-কল নির্মূলের জন্য রানটাইম-স্তরের সমর্থন প্রয়োজন।

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

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


দীর্ঘ সংস্করণ:

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

জাভা শুরু থেকেই একটি অপরিহার্য , অবজেক্ট-ওরিয়েন্টেড ভাষা হিসাবে ডিজাইন করা হয়েছিল ।

  • অপরিহার্য ভাষাগুলি প্রায়শই কোনও না কোনও রূপের পরিবর্তনশীল ভেরিয়েবলের উপর নির্ভর করে। তারা পুনরাবৃত্তির উপর পুনরাবৃত্তির পক্ষে থাকে, উদাহরণস্বরূপ, এবং প্রায় সমস্ত পুনরাবৃত্ত গঠন - এমনকি while (true)এবং for (;;)! - পুনরুক্তি থেকে পুনরাবৃত্তিতে পরিবর্তিত কোথাও পরিবর্তনশীলটির উপর সম্পূর্ণ নির্ভরশীল।
  • অবজেক্ট-ওরিয়েন্টেড ভাষাগুলি প্রতিটি প্রোগ্রামকে একে অপরের কাছে বার্তা প্রেরণ করার গ্রাফ হিসাবে প্রায় প্রতিটি প্রোগ্রামের কল্পনা করে, এবং প্রায় সমস্ত ক্ষেত্রেই কোনও কিছুর পরিবর্তন করে সেই বার্তাগুলির প্রতিক্রিয়া জানায়।

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

সুতরাং, সমস্ত ব্যবহারিক উদ্দেশ্যে, আমরা আমাদের নিজস্ব কোড থেকে ভেরিয়েবলগুলি নিষিদ্ধ করার মধ্যে সীমাবদ্ধ । ঠিক আছে, আমরা কিন্ডা করতে পারি। প্রায়। মূলত আমাদের যা প্রয়োজন তা হ'ল প্রায় সমস্ত পুনরাবৃত্তি পুনরাবৃত্তির সাথে প্রতিস্থাপন করা এবং পরিবর্তিত মান প্রত্যাবর্তনকারী পুনরাবৃত্ত কলগুলির সাথে সমস্ত রূপান্তর। তাই ভালো...

class Ints {
     final int value;
     final Ints tail;

     public Ints(int value, Ints rest) {
         this.value = value;
         this.tail = rest;
     }
     public Ints next() { return this.tail; }
     public int value() { return this.value; }
}

public Ints take(int count, Ints input) {
    if (count == 0 || input == null) return null;
    return new Ints(input.value(), take(count - 1, input.next()));
}    

public Ints squares_of(Ints input) {
    if (input == null) return null;
    int i = input.value();
    return new Ints(i * i, squares_of(input.next()));
}

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

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

public function doStuff() {
    final Ints integers = ...somehow assemble list of 20 million ints...;
    final Ints result = take(25, squares_of(integers));
    ...
}

যদিও ফলাফলের জন্য আমাদের কেবল 25 টি ints প্রয়োজন, এটি squares_ofজানে না। এটি প্রতিটি সংখ্যার স্কয়ারটি ফিরিয়ে দিতে চলেছে integers। 20 মিলিয়ন স্তরের গভীর পুনরাবৃত্তি জাভাতে বেশ বড় সমস্যা তৈরি করে।

দেখুন, কার্যকরী ভাষাগুলির মধ্যে আপনি সাধারণত এ জাতীয় উদ্বেগ প্রকাশ করেন, "লেজ কল বিলোপ" নামে একটি বৈশিষ্ট্য রয়েছে। এর অর্থ কী, যখন সংকলকটি কোডটির শেষ কাজটিকে নিজের কল করতে দেখায় (এবং ফাংশনটি অকার্যকর থাকে তবে ফলাফলটি ফেরত দেয়), এটি একটি নতুন সেট আপ না করে বর্তমান কলের স্ট্যাক ফ্রেম ব্যবহার করে এবং পরিবর্তে একটি "জাম্প" করে একটি "কল" (যাতে ব্যবহৃত স্ট্যাক স্পেস স্থির থাকে) of সংক্ষেপে, এটি পূর্বে-পুনরাবৃত্তিকে পুনরাবৃত্তিতে পরিণত করার দিকে প্রায় 90% পথ যায় way এটি স্ট্যাককে উপচে না ফেলে সেই বিলিয়ন ইনটগুলির সাথে কাজ করতে পারে। (এটি অবশেষে স্মৃতিশক্তি থেকে সরে যেতে চাইবে, তবে এক বিলিয়ন ইনটসের তালিকা জড়ো করা আপনাকে 32-বিট সিস্টেমে যাইহোক স্মৃতিশক্তির দিকে জড়িয়ে ফেলবে))

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

একটি আধা-কার্যত ... অলস মূল্যায়ন। আমাদের এখনও স্ট্যাকের সীমাবদ্ধতা রয়েছে তবে সেগুলির সাথে আমাদের আরও নিয়ন্ত্রণের কারণগুলির সাথে যুক্ত হতে পারে। আমাদের কেবল 25 ফিরিয়ে দিতে মিলিয়ন ইনট গণনা করতে হবে না :) :)

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

// Represents something that can give us instances of OutType.
// We can basically treat this class like a list.
interface Source<OutType> {
     public Source<OutType> next();
     public OutType value();
}

// Represents an operation that turns an InType into an OutType.
// Note, these can be the same type.  We're just flexible like that.
interface Transform<InType, OutType> {
    public OutType appliedTo(InType input);
}

// Represents an action (as opposed to a function) that can run on
// every element of a sequence.
abstract class Action<InType> {
    abstract void doWith(final InType input);
    public void doWithEach(final Source<InType> input) {
        if (input == null) return;
        doWith(input.value());
        doWithEach(input.next());
    }
}

// A list of Integers.
class Ints implements Source<Integer> {
     final Integer value;
     final Ints tail;
     public Ints(Integer value, Ints rest) {
         this.value = value;
         this.tail = rest;
     }
     public Ints(Source<Integer> input) {
         this.value = input.value();
         this.tail = new Ints(input.next());
     }
     public Source<Integer> next() { return this.tail; }
     public Integer value() { return this.value; }
     public static Ints fromArray(Integer[] input) {
         return fromArray(input, 0, input.length);
     }
     public static Ints fromArray(Integer[] input, int start, int end) {
         if (end == start || input == null) return null;
         return new Ints(input[start], fromArray(input, start + 1, end));
     }
}

// An example of the spiff we get by splitting the "iterator" interface
// off.  These ints are effectively generated on the fly, as opposed to
// us having to build a huge list.  This saves huge amounts of memory
// and CPU time, for the rather common case where the whole sequence
// isn't needed.
class Range implements Source<Integer> {
    final int start, end;
    public Range(int start, int end) {
        this.start = start;
        this.end = end;
    }
    public Integer value() { return start; }
    public Source<Integer> next() {
        if (start >= end) return null;
        return new Range(start + 1, end);
    }
}

// This takes each InType of a sequence and turns it into an OutType.
// This *takes* a Transform, rather than just *implementing* Transform,
// because the transforms applied are likely to be specified inline.
// If we just let people override `value()`, we wouldn't easily know what type
// to return, and returning our own type would lose the transform method.
static class Mapper<InType, OutType> implements Source<OutType> {
    private final Source<InType> input;
    private final Transform<InType, OutType> transform;

    public Mapper(Transform<InType, OutType> transform, Source<InType> input) {
        this.transform = transform;
        this.input = input;
    }

    public Source<OutType> next() {
         return new Mapper<InType, OutType>(transform, input.next());
    }
    public OutType value() {
         return transform.appliedTo(input.value());
    }
}

// ...

public <T> Source<T> take(int count, Source<T> input) {
    if (count <= 0 || input == null) return null;
    return new Source<T>() {
        public T value() { return input.value(); }
        public Source<T> next() { return take(count - 1, input.next()); }
    };
}

(মনে রাখবেন যে এটি যদি জাভাতে প্রকৃতপক্ষে কার্যকর হয় তবে উপরের মত কিছুটা কোড ইতিমধ্যে এপিআইয়ের অংশ হতে পারে))

এখন, জায়গায় একটি পরিকাঠামো রয়েছে, কোড লিখতে এটি বরং তুচ্ছ, যা পারস্পরিক পরিবর্তনশীলগুলির প্রয়োজন হয় না এবং কম পরিমাণে ইনপুটের জন্য কমপক্ষে স্থিতিশীল।

public Source<Integer> squares_of(Source<Integer> input) {
     final Transform<Integer, Integer> square = new Transform<Integer, Integer>() {
         public Integer appliedTo(final Integer i) { return i * i; }
     };
     return new Mapper<>(square, input);
}


public void example() {
    final Source<Integer> integers = new Range(0, 1000000000);

    // and, as for the author's "bet you can't do this"...
    final Source<Integer> squares = take(25, squares_of(integers));

    // Just to make sure we got it right :P
    final Action<Integer> printAction = new Action<Integer>() {
        public void doWith(Integer input) { System.out.println(input); }
    };
    printAction.doWithEach(squares);
}

এটি বেশিরভাগ ক্ষেত্রেই কাজ করে তবে এটি ওভারফ্লোগুলি স্ট্যাকের জন্য কিছুটা প্রবণ। take2 বিলিয়ন ইন্ট ইনং করার চেষ্টা করুন এবং তাদের উপর কিছু পদক্ষেপ নিন। : পি এটি অবশেষে একটি ব্যতিক্রম ছুঁড়ে ফেলবে, কমপক্ষে +৪+ জিবি র‌্যাম স্ট্যান্ডার্ড হওয়া পর্যন্ত। সমস্যাটি হ'ল, কোনও প্রোগ্রামের মেমরির পরিমাণ এটির স্ট্যাকের জন্য সংরক্ষিত থাকে that এটি সাধারণত 1 থেকে 8 MiB এর মধ্যে থাকে। (আপনি বড় জন্য অনুরোধ করতে পারেন, কিন্তু এটা যে সব অনেক আপনি কত জন্য অনুরোধ কোন ব্যাপার না - আপনি কল take(1000000000, someInfiniteSequence), আপনি হবে । একটি ব্যতিক্রম পাবেন) সৌভাগ্যবসত, অলস মূল্যায়ন সঙ্গে, দুর্বল স্পট একটি এলাকায় আমরা আরো ভালো করতে পারেন নিয়ন্ত্রণ । আমরা শুধু আমাদের কত যত্ন নিতে হবে take()

এটি এখনও স্কেলিং আপ প্রচুর সমস্যা হবে, কারণ আমাদের স্ট্যাক ব্যবহার রৈখিকভাবে বৃদ্ধি। প্রতিটি কল একটি উপাদান পরিচালনা করে এবং বাকীটি অন্য কলটিতে চলে। এখন আমি এটি সম্পর্কে চিন্তা করি, যদিও, একটি কৌশল আমরা টানতে পারি যা আমাদের আরও খানিকটা হেডরুম অর্জন করতে পারে: কলগুলির শৃঙ্খলে কল গাছকে পরিণত করুন। এর মতো আরও কিছু বিবেচনা করুন:

public <T> void doSomethingWith(T input) { /* magic happens here */ }
public <T> Source<T> workWith(Source<T> input, int count) {
    if (count < 0 || input == null) return null;
    if (count == 0) return input;
    if (count == 1) {
        doSomethingWith(input.value());
        return input.next();
    }
    return (workWith(workWith(input, count/2), count - count/2);
}

workWithমূলত কাজটি দুটি ভাগে বিভক্ত করে এবং প্রতিটি অর্ধেককে অন্য কলটিতে অর্পণ করে। যেহেতু প্রতিটি কল কাজের তালিকার আকার একের চেয়ে অর্ধেক কমিয়ে দেয়, সুতরাং এটি লৈঙ্গিকতার চেয়ে রৈখিকতার চেয়ে স্কেল করা উচিত।

সমস্যাটি হ'ল, এই ফাংশনটি একটি ইনপুট চায় - এবং একটি লিঙ্কযুক্ত তালিকার সাথে দৈর্ঘ্য পেতে পুরো তালিকাটি অনুসরণ করতে হবে। এটি সহজে সমাধান করা যায়, যদিও; কেবল পরোয়া করি না আছে কত এন্ট্রি। :) উপরের কোডটি Integer.MAX_VALUEগণনার মতো কিছু নিয়ে কাজ করবে , যেহেতু নাল কোনওভাবেই প্রক্রিয়াজাতকরণ বন্ধ করে দেয়। গণনাটি বেশিরভাগ সেখানে থাকে তাই আমাদের কাছে একটি শক্ত বেস মামলা রয়েছে। যদি আপনি Integer.MAX_VALUEকোনও তালিকায় এন্ট্রি বেশি রাখার প্রত্যাশা করেন , তবে আপনি workWithতার ফেরতের মানটি পরীক্ষা করতে পারেন - এটি শেষে নালাগুলি হওয়া উচিত। অন্যথায়, পুনরাবৃত্তি।

মনে রাখবেন, এটি যতটা উপাদানকে আপনি বলেছেন তেমন এটি স্পর্শ করে। এটি অলস নয়; এটি অবিলম্বে তার কাজ করে। আপনি এটি কেবল ক্রিয়াকলাপের জন্যই করতে চান - এটি হ'ল জিনিস যাঁর একমাত্র উদ্দেশ্য তালিকার প্রতিটি উপাদানটিতে নিজেকে প্রয়োগ করা। যেহেতু আমি এই মুহূর্তে এটি ভাবছি, আমার কাছে মনে হচ্ছে লিনিয়ারটি রাখলে ক্রমগুলি অনেক কম জটিল হবে; কোনও সমস্যা হওয়া উচিত নয়, যেহেতু সিক্যুয়েন্সগুলি তাদেরকে যেভাবেই কল করে না - তারা কেবল এমন বস্তু তৈরি করে যা তাদের আবার কল করে।


3

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

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

এটা তোলে মত কিছু ব্যবহার করা জরুরী Seqবা Iteratorযেমন মানে তালিকা প্রখর রৌদ্রে তৈরি করা হয় ইন্টারফেসগুলি। Iteratorইন্টারফেস, একটি অপরিবর্তনীয় বস্তুর হতে পারে না, যাতে কম কার্যকরী প্রোগ্রামিং উপযুক্ত হয় - যদি আপনি না বলতে পারেন আপনি যদি একটি ফাংশন মধ্যে পাস মান এটি দ্বারা পরিবর্তন করা হয়েছে, তাহলে আপনি কার্যকরী প্রোগ্রামিং চাবি সুবিধার এক হারান।

স্পষ্টতই integersসমস্ত পূর্ণসংখ্যার একটি তালিকা হওয়া উচিত, তাই আমি শূন্য থেকে শুরু করেছি এবং পর্যায়ক্রমে ইতিবাচক এবং নেতিবাচকগুলি ফিরে পেয়েছি।

স্কোয়ারের দুটি সংস্করণ রয়েছে - একটি কাস্টম সিকোয়েন্স তৈরি করে, অন্যটি ব্যবহার করে mapযা একটি 'ফাংশন' নেয় - জাভা 7 তে ল্যাম্বডাস থাকে না তাই আমি একটি ইন্টারফেস ব্যবহার করেছি - এবং ক্রমান্বয়ে প্রতিটি উপাদানটিতে এটি প্রয়োগ করি।

square ( int x )ফাংশনটির বিন্দুটি কেবলমাত্র head()দুবার কল করার প্রয়োজনটি সরিয়ে ফেলতে হয় - সাধারণত আমি মানটি একটি চূড়ান্ত ভেরিয়েবলের মধ্যে রেখে এই কাজটি করতাম তবে এই ফাংশনটি যুক্ত করার অর্থ প্রোগ্রামটিতে কোনও ভেরিয়েবল নেই, কেবলমাত্র ফাংশন প্যারামিটার।

এই ধরণের প্রোগ্রামিংয়ের জন্য জাভাটির ভারবোসিটি আমাকে তার পরিবর্তে C99 এ আমার দোভাষীর দ্বিতীয় সংস্করণ লিখতে বাধ্য করেছিল।

public class Squares {
    interface Seq<T> {
        T head();
        Seq<T> tail();
    }

    public static void main (String...args) {
        print ( take (25, integers ) );
        print ( take (25, squaresOf ( integers ) ) );
        print ( take (25, squaresOfUsingMap ( integers ) ) );
    }

    static Seq<Integer> CreateIntSeq ( final int n) {
        return new Seq<Integer> () {
            public Integer head () {
                return n;
            }
            public Seq<Integer> tail () {
                return n > 0 ? CreateIntSeq ( -n ) : CreateIntSeq ( 1 - n );
            }
        };
    }

    public static final Seq<Integer> integers = CreateIntSeq(0);

    public static Seq<Integer> squaresOf ( final Seq<Integer> source ) {
        return new Seq<Integer> () {
            public Integer head () {
                return square ( source.head() );
            }
            public Seq<Integer> tail () {
                return squaresOf ( source.tail() );
            }
        };
    }

    // mapping a function over a list rather than implementing squaring of each element
    interface Fun<T> {
        T apply ( T value );
    }

    public static Seq<Integer> squaresOfUsingMap ( final Seq<Integer> source ) {
        return map ( new Fun<Integer> () {
            public Integer apply ( final Integer value ) {
                return square ( value );
            }
        }, source );
    }

    public static <T> Seq<T> map ( final Fun<T> fun, final Seq<T> source ) {
        return new Seq<T> () {
            public T head () {
                return fun.apply ( source.head() );
            }
            public Seq<T> tail () {
                return map ( fun, source.tail() );
            }
        };
    }

    public static Seq<Integer> take ( final int count,  final Seq<Integer> source ) {
        return new Seq<Integer> () {
            public Integer head () {
                return source.head();
            }
            public Seq<Integer> tail () {
                return count > 0 ? take ( count - 1, source.tail() ) : nil;
            }
        };
    }

    public static int square ( final int x ) {
        return x * x;
    }

    public static final Seq<Integer> nil = new Seq<Integer> () {
        public Integer head () {
            throw new RuntimeException();
        }
        public Seq<Integer> tail () {
            return this;
        }
    };

    public static <T> void print ( final Seq<T> seq ) {
        printPartSeq ( "[", seq.head(), seq.tail() );
    }

    private static <T> void printPartSeq ( final String prefix, final T value, final Seq<T> seq ) {
        if ( seq == nil) {
            System.out.println("]");
        } else {
            System.out.print(prefix);
            System.out.print(value);
            printPartSeq ( ",", seq.head(), seq.tail() );
        }
    }
}

3

পরিবর্তনীয় ভেরিয়েবল ব্যবহার না করে কীভাবে দরকারী জাভা প্রোগ্রাম লিখতে হয়।

আপনি তত্ত্বের সাথে জাভাতে কেবল পুনরাবৃত্তি এবং কোনও পরিবর্তনীয় ভেরিয়েবল ব্যবহার করে যা কিছু বাস্তবায়ন করতে পারেন।

প্রস্তুতিতে:

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

  • গ্রন্থাগারগুলির জন্য ডিট্টো। এবং আপনি যদি লাইব্রেরি ক্লাসগুলিতে নিজেকে সীমাবদ্ধ করেন যা প্রচ্ছদের অধীনে মিউটেশন ব্যবহার করে না তবে এটি আরও শক্ত। (আপনি স্ট্রিং ব্যবহার করতে পারবেন না ... কীভাবে hashcodeপ্রয়োগ করা হয় তা একবার দেখুন ))

  • মূলধারার জাভা প্রয়োগগুলি টেল-কল অপ্টিমাইজেশান সমর্থন করে না। এর অর্থ হল যে অ্যালগরিদমের পুনরাবৃত্ত সংস্করণগুলি স্ট্যাক স্পেস "ক্ষুধার্ত" হয়ে থাকে। এবং যেহেতু জাভা থ্রেড স্ট্যাকগুলি বৃদ্ধি পাচ্ছে না তাই আপনার বড় স্ট্যাকগুলি প্রিলোকল্ট করা প্রয়োজন ... বা ঝুঁকি StackOverflowError

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

(তবে ওহে, ওকে ঠিক আছে। জেভিএমের জন্য অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজ উপলব্ধ রয়েছে, যার মধ্যে কয়েকটি ফাংশনাল প্রোগ্রামিং সমর্থন করে))


2

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

cat /dev/zero | tr '\0' '\n' | cat -n | awk '{ print $0 * $0 }' | head 25

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

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

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

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

তারপরে আবারও, কোনও জায়গায় জাভা প্রোগ্রামারকে কার্যকরী প্রোগ্রামিং থেকে অনুপ্রেরণা নেওয়া ভাল ধারণা হতে পারে।

সম্প্রতি আমার প্রিয় কৌশলটি ছিল একটি অপরিবর্তনীয়, অবিচ্ছিন্ন রিটার্ন ভেরিয়েবল এবং একক প্রস্থান ব্যবহার করার জন্য যাতে কিছু কার্যকরী ভাষা সংকলক করেন, জাভা পরীক্ষা করে যে ফাংশনটির শরীরে যা ঘটুক না কেন, আমি সর্বদা একটি এবং কেবল একটি সরবরাহ করি ফেরত মূল্য. উদাহরণ:

int f(final int n) {
    final int result; // not initialized here!
    if (n < 0) {
        result = -n;
    } else if (n < 1) {
        result = 0;
    } else {
        result = n - 1;
    }
    // If I would leave off the "else" clause,
    // Java would fail to compile complaining that
    // "result" is possibly uninitialized.
    return result;
}


আমি প্রায় 70০% নির্দিষ্ট জাভা ইতিমধ্যে যাইহোক রিটার্ন মান পরীক্ষা করে দেখছি। নিয়ন্ত্রণ যদি একটি অকার্যকর ফাংশন শেষ হয়ে যেতে পারে তবে আপনার একটি "নিখুঁত রিটার্ন স্টেটমেন্ট" সম্পর্কে একটি ত্রুটি পাওয়া উচিত।
সিএইচও

আমার বক্তব্য: আপনি যদি এটি কোড করে থাকেন যেমন int result = -n; if (n < 1) { result = 0 } return result;এটি ঠিক সূক্ষ্ম সংকলন করে এবং সংকলকটির কোনও ধারণা নেই যা আপনি এটি আমার উদাহরণে ফাংশনটির সমতুল্য করতে চেয়েছিলেন কিনা। কৌশলটি সহায়ক হিসাবে দেখানোর জন্য উদাহরণটি খুব সহজ, তবে প্রচুর শাখাসমূহের সাথে একটি ফাংশনে আমার মনে হয় যে পরিষ্কার হয়ে গেছে যে ফলাফলটি একবারেই নির্ধারিত হয় নির্বিশেষে কোন পথ অনুসরণ করা হয়।
মিনিপ্রেট

আপনি যদি বলেন if (n < 1) return 0; else return -n;তবে কোনও সমস্যা নেই ... এবং এগুলি ছাড়াও এটি আরও সহজ। :) আমার কাছে মনে হয় যে সেক্ষেত্রে, "এক রিটার্ন" বিধিটি আসলে আপনার রিটার্নের মান কখন নির্ধারণ করা হয়েছিল তা না জানার কারণকে সহায়তা করে ; অন্যথায়, আপনি কেবল এটি ফিরিয়ে দিতে পারবেন এবং জাভা কখন নির্ধারণ করতে সক্ষম হবে যে যখন অন্য পাথগুলি কোনও মান ফেরত না দেয়, কারণ আপনি এটির আসল প্রত্যাবর্তন থেকে আর মানের গণনা তালাক দিচ্ছেন না।
সিএওও

অথবা, আপনার উত্তরের উদাহরণের জন্য if (n < 0) return -n; else if (n == 0) return 0; else return n - 1;,।
সিএইচও

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

0

এটির সন্ধানের সবচেয়ে সহজ উপায় হ'ল নিম্নোক্ত ফ্রেজ সংকলকটিকে ফিড করা এবং উত্পন্ন জাভা কোডটি দেখুন:

module Main where

result = take 25 (map sqr [1..]) where sqr x = x*x

কিছু দিন পরে আমি আমার উত্তরগুলি এই উত্তরে ফিরে পেয়েছি। আমার সমস্ত পরামর্শের পরেও ছিল স্কালায় ক্রিয়ামূলক প্রোগ্রামিং অংশগুলি বাস্তবায়ন করা। যদি আমরা সেই জায়গাগুলিতে যেখানে স্কেল প্রয়োগ করা বিবেচনা করি যেখানে হাস্কেলের কথা সত্যিই আমাদের মনে ছিল (এবং আমি মনে করি যে আমি একমাত্র Blog.zlemma.com/2013/02/20/… না ) তবে আমাদের কমপক্ষে ফ্রিজকে বিবেচনা করা উচিত নয়?
মিনিপ্রেট

@ এমনোপ্রেট এটি প্রকৃতপক্ষে কুলুঙ্গিটি হ'ল - এমন লোকেরা যারা হাস্কেলকে জানতে ও ভালবাসে এবং এখনও জেভিএমের প্রয়োজন হয় need আমি বিশ্বাস করি একদিন ফ্রিজ কমপক্ষে গুরুতর বিবেচনার জন্য যথেষ্ট পরিপক্ক হবে।
ইঙ্গো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.