টাইপ পরীক্ষক খুব ভুল টাইপ প্রতিস্থাপনের অনুমতি দিচ্ছে, এবং প্রোগ্রামটি এখনও সংকলন করে


100

আমার প্রোগ্রামে কোনও সমস্যা ডিবাগ করার চেষ্টা করার সময় (গ্লোস ব্যবহার করে সমান ব্যাসার্ধ সহ 2 টি বৃত্ত বিভিন্ন আকারে আঁকানো হচ্ছে *), আমি এক বিস্ময়কর পরিস্থিতি পেরিয়ে গিয়েছি। আমার ফাইল যা বস্তুগুলি পরিচালনা করে, তার জন্য আমার নিম্নলিখিত সংজ্ঞা রয়েছে Player:

type Coord = (Float,Float)
data Obj =  Player  { oPos :: Coord, oDims :: Coord }

এবং আমার মূল ফাইলে, যা অবজেক্টস.এফএস আমদানি করে, আমার নিম্নলিখিত সংজ্ঞা রয়েছে:

startPlayer :: Obj
startPlayer = Player (0,0) 10

আমার প্লেয়ারের জন্য ক্ষেত্রগুলি যুক্ত করার এবং পরিবর্তন করার কারণে, এবং startPlayerপরে আপডেট করতে ভুলে যাওয়ার কারণে ঘটেছে (এর মাত্রাগুলি একটি ব্যাসার্ধের প্রতিনিধিত্ব করার জন্য একক সংখ্যা দ্বারা নির্ধারিত হয়েছিল, তবে আমি এটি Coordপ্রতিনিধিত্ব করতে (প্রস্থ, উচ্চতা) এ পরিবর্তন করেছি ; যদি আমি কখনও তৈরি করি তবে প্লেয়ারটি একটি চেনাশোনা ছাড়াই اعتراض করে)।

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

আমি প্রথমে ভেবেছিলাম আমার কাছে ফাইলগুলির বিভিন্ন সংস্করণ খোলা আছে তবে কোনও ফাইলের কোনও পরিবর্তন সংকলিত প্রোগ্রামে প্রতিফলিত হয়েছে।

পরবর্তী আমি ভেবেছিলাম যে সম্ভবত startPlayerকোনও কারণে ব্যবহৃত হচ্ছে না। আউট মন্তব্য startPlayerকম্পাইলার ত্রুটি যদিও, এবং এমনকি নবজাতক উৎপাদ পরিবর্তন 10মধ্যে startPlayerকারণ একটি যথাযথ প্রতিক্রিয়া (এর শুরু আকার পরিবর্তন Player); আবার, এটি ভুল ধরণের হওয়া সত্ত্বেও। এটি ডেটা সংজ্ঞাটি সঠিকভাবে পড়ছে তা নিশ্চিত করার জন্য, আমি ফাইলে একটি টাইপো প্রবেশ করিয়ে দিয়েছি এবং এটি আমাকে একটি ত্রুটি দিয়েছে; তাই আমি সঠিক ফাইলটি দেখছি।

আমি তাদের নিজস্ব ফাইলে উপরে 2 স্নিপেট পেস্ট চেষ্টা, এবং এটি প্রত্যাশিত ত্রুটি যা দ্বিতীয় ক্ষেত্র থুথু Playerমধ্যে startPlayerভুল।

এটি সম্ভবত কী হতে দেয়? আপনি মনে করেন যে এটিই হ্যাস্কেলের ধরণের পরীক্ষককে প্রতিরোধ করা উচিত।


* আমার আসল সমস্যার উত্তর, সমান ব্যাসার্ধের দুটি চেনাশোনা বিভিন্ন আকারে আঁকছে, এটি ছিল যে রেডিয়ির একটি আসলে নেতিবাচক ছিল।


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

4
সম্পন্ন. উদাহরণগুলি বাদ দেওয়া কি সম্ভব? গ্রন্থাগারটি সঞ্চালনের জন্য তাদের এটি প্রয়োজন হতে পারে তবে আমার এটির দরকার নেই। আমি এটিও লক্ষ্য করেছি যে তারা নূম বর্ণকে সংজ্ঞায়িত করেছে। এটি আমাকে ছিনিয়ে নেওয়ার আগে সময়ের বিষয় মাত্র।
কারসিকেনিকেট

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

4
@ ক্রিশ্চিয়ান্সকোনকলে এমন একটি সুযোগ আছে যা টকসামের নামটি কী করে তা টকটকে লেখক বুঝতে পারেন নি। যাই হোক, এই সত্যিই দূরে যেতে (হয় করা প্রয়োজন Pointএকটি newtypeবা Ala অন্যান্য অপারেটর নাম ব্যবহার linear)
ঘনকীয়

4
@ কিউবিক: টাইপসাইনামআইনমেন্টসটি নিজে থেকে তেমন খারাপ নয় (যদিও সম্পূর্ণ নিরীহ নয়) তবে আপনি যখন এটি ওভারল্যাপিংয়ের সাথে যুক্ত করেন তখন জিনিসগুলি খুব মজাদার হয়।
জন এল

উত্তর:


128

যদি কোনও Num (Float,Float)উদাহরণ উপস্থিত থাকে তবে এটি সম্ভবত সংকলন করতে পারে way এটি স্ট্যান্ডার্ড লাইব্রেরি দ্বারা সরবরাহ করা হয়নি, যদিও আপনি সম্ভবত যে লাইব্রেরি ব্যবহার করছেন তার মধ্যে কোনও একটি এটি পাগল কারণে যুক্ত করেছে। আপনার প্রকল্পটি ghci এ লোড করার চেষ্টা করুন এবং দেখুন কিনা 10 :: (Float,Float)কাজ করে দেখুন, তবে :i Numউদাহরণটি কোথা থেকে আসছে তা খুঁজে বের করার চেষ্টা করুন এবং তারপরে যাকে এটি সংজ্ঞায়িত করেছেন তার জন্য চিৎকার করুন।

সংযোজন: দৃষ্টান্তগুলি বন্ধ করার কোনও উপায় নেই। এমনকি সেখানে একটি উপায় নয় না তাদেরকে মডিউল থেকে রপ্তানি করুন। যদি এটি সম্ভব হয় তবে এটি আরও বেশি বিভ্রান্তিকর কোডের দিকে নিয়ে যাবে। এখানে আসল সমাধান হ'ল এর মতো দৃষ্টান্তগুলি সংজ্ঞায়িত না করা।


53
কি দারুন. 10 :: (Float, Float)ফলন হয় (10.0,10.0)এবং :i Numএতে লাইন থাকে instance Num Point -- Defined in ‘Graphics.Gloss.Data.Point’( Pointএটি কর্ডের গ্লসের উপনাম)। সিরিয়াসলি? ধন্যবাদ. এটি আমাকে নিদ্রাহীন রাত থেকে বাঁচিয়েছে।
কারসিজিনিট

6
@ কারসিজেনিকেট যদিও এ জাতীয় দৃষ্টান্ত অস্বীকার করার পক্ষে একে অপ্রয়োজনীয় মনে হয়, তবে এর অনুমতি দেওয়ার কারণটি বিকাশকারীরা Numযেখানে এটি বোধগম্য তার নিজস্ব উদাহরণ লিখতে পারে যেমন একটি Angleডেটা টাইপ যা এর মধ্যে সীমাবদ্ধ Doubleকরে -piএবং piঅথবা যদি কোনও ডেটা টাইপ লিখতে চায় কোয়ার্টারিয়ন বা আরও কিছু জটিল সংখ্যার প্রকারের প্রতিনিধিত্ব করা এই বৈশিষ্ট্যটি খুব সুবিধাজনক। এটি String/ Text/ হিসাবে একই নিয়ম অনুসরণ করে ByteString, এই দৃষ্টান্তগুলিকে ব্যবহারের সহজ-দৃষ্টিকোণ থেকে বোঝা যায়, তবে এটি এই ক্ষেত্রে যেমন অপব্যবহার করা যায়।
ভেকলিলার

4
@ ভেকলিলার আমি নমসের উদাহরণ দেওয়ার প্রয়োজনীয়তা বুঝতে পারি understand "WOW" কয়েকটি জিনিস থেকে শুরু হয়েছিল। আমি জানতাম না যে আপনি টাইপ এলিয়াসের উদাহরণ তৈরি করতে পারেন, একটি কর্ডের একটি নুম উদাহরণ তৈরি করা কেবল স্বতঃস্ফূর্ত মনে হয়, এবং আমি এটির কথা ভাবিনি। ওহ ভাল, পাঠ শিখেছি।
কারসিজেনিকেট

4
এটির পরিবর্তে একটি newtypeঘোষণাপত্র ব্যবহার করে আপনি আপনার গ্রন্থাগার থেকে অনাথ দৃষ্টান্ত দিয়ে আপনার সমস্যার সমাধান করতে পারেন । Coordtype
বেঞ্জামিন হজসন

4
@ কার্সিজেনিকেট আমি বিশ্বাস করি যে টাইপ প্রতিশব্দগুলির উদাহরণগুলির জন্য আপনার অনুমতি দিতে -XTypeSynonymInferences প্রয়োজন , তবে সমস্যাযুক্ত উদাহরণটি তৈরি করার জন্য এটি প্রয়োজনীয় নয়। এর জন্য Num (Float, Float)বা এমনকি (Floating a) => Num (a,a)কোনও উদাহরণের জন্য এক্সটেনশানটির প্রয়োজন হবে না তবে একই আচরণের ফলাফল হবে।
crockeea

64

হাস্কেলের ধরণের পরীক্ষক যুক্তিসঙ্গত হচ্ছে। সমস্যাটি হ'ল আপনি যে লাইব্রেরিটি ব্যবহার করছেন তার লেখকরা কিছু করেছেন ... কম যুক্তিসঙ্গত।

সংক্ষিপ্ত উত্তরটি হ'ল: হ্যাঁ, 10 :: (Float, Float)যদি কোনও উদাহরণ থাকে তবে তা পুরোপুরি কার্যকর Num (Float, Float)। সংকলকের বা ভাষার দৃষ্টিকোণ থেকে এটি সম্পর্কে "খুব ভুল" কিছুই নেই। এটি সংখ্যাগত আক্ষরিক কী করে তা আমাদের স্বজ্ঞাততার সাথে বর্গক্ষেত্র নয়। যেহেতু আপনি যে ধরণের ত্রুটি করেছেন তার ধরণের সিস্টেমটি আপনি অভ্যস্ত, সুতরাং আপনি ন্যায়সঙ্গতভাবে অবাক এবং হতাশ!

Numউদাহরণস্বরূপ এবং fromIntegerসমস্যা

আপনি অবাক হলেন যে সংকলক গ্রহণ করে 10 :: Coord, যেমন 10 :: (Float, Float)। এটি ধরে নেওয়া যুক্তিসঙ্গত যে সংখ্যাসূচক অক্ষরগুলিকে 10"সংখ্যাসূচক" প্রকারের অনুমান করা হবে। বাক্সের বাইরে, সাংখ্যিক লিটারেল ব্যাখ্যা করা যেতে পারে যেমন Int, Integer, Float, অথবা Double। সংখ্যাগুলির একটি দ্বিগুণ, অন্য কোনও প্রসঙ্গ নয়, এই চার প্রকারের সংখ্যাটি যেভাবে একটি সংখ্যা বলে মনে হয় না। আমরা যে বিষয়ে কথা না Complex

ভাগ্যক্রমে বা দুর্ভাগ্যক্রমে, তবে, হাস্কেল একটি খুব নমনীয় ভাষা। মানটি নির্দিষ্ট করে যে কোনও পূর্ণসংখ্যার আক্ষরিক মতোকে 10ব্যাখ্যা করা হবে fromInteger 10, যা টাইপ করে Num a => a। সুতরাং এটির জন্য উদাহরণ লিখেছে এমন কোনও ধরণের 10হিসাবে অনুমান করা যায়। আমি এটি আরও উত্তরে আরেকটি উত্তরে ব্যাখ্যা করি ।Num

সুতরাং আপনি যখন আপনার প্রশ্ন পোস্ট করেছেন, একজন অভিজ্ঞ হাস্কেলর তত্ক্ষণাত স্পষ্ট করে দিয়েছিলেন যে 10 :: (Float, Float)গ্রহণযোগ্য হওয়ার জন্য , এর মতো Num a => Num (a, a)উদাহরণ থাকতে হবে বা Num (Float, Float)। এর মধ্যে এরকম কোনও উদাহরণ নেই Prelude, সুতরাং এটি অন্য কোথাও সংজ্ঞায়িত করা উচিত। প্যাকেজটি ব্যবহার করে :i Numআপনি খুব তাড়াতাড়ি চিহ্নিত করেছেন gloss

প্রতিশব্দ এবং এতিম দৃষ্টান্ত টাইপ করুন

তবে এক মিনিট ধরে রাখুন। আপনি glossএই উদাহরণে কোনও ধরণের ব্যবহার করছেন না ; উদাহরণটি glossআপনাকে প্রভাবিত করেছিল কেন ? উত্তর দুটি ধাপে আসে।

প্রথমত, কীওয়ার্ডের সাথে প্রবর্তিত কোনও প্রকারের সমার্থক শব্দটি typeকোনও নতুন ধরণের তৈরি করে না । আপনার মডিউলে, লেখার Coordজন্য কেবল সংক্ষিপ্তকরণ (Float, Float)। একইভাবে Graphics.Gloss.Data.Point, Pointমানে (Float, Float)। অন্য কথায়, আপনার Coordএবং glossএর Pointআক্ষরিক সমতুল্য।

সুতরাং glossরক্ষণাবেক্ষণকারীরা যখন লিখতে পছন্দ করেছেন instance Num Point where ..., তারা আপনার Coordটাইপটিকে একটি উদাহরণও তৈরি করেছেন Num। এটি instance Num (Float, Float) where ...বা এর সমতুল্য instance Num Coord where ...

(ডিফল্টরূপে, হাস্কেল টাইপ প্রতিশব্দটিকে শ্রেণীর উদাহরণ হিসাবে মঞ্জুরি দেয় না uth glossলেখকদের ভাষা এক্সটেনশনের একটি জোড়া সক্ষম করতে হবে TypeSynonymInstancesএবং FlexibleInstancesউদাহরণটি লিখতে হবে))

দ্বিতীয়ত, এটি আশ্চর্যজনক কারণ এটি একটি অনাথ উদাহরণ , উদাহরণস্বরূপ একটি ঘোষণার instance C Aযেখানে উভয়ই Cএবং Aঅন্যান্য মডিউলগুলিতে সংজ্ঞায়িত। এখানে এটা কারণ প্রতিটি অংশ জড়িত বিশেষ করে কুটিল আছে, অর্থাত Num, (,)এবং Floatথেকে আসে Preludeএবং সর্বত্র সুযোগ হতে পারে।

আপনার প্রত্যাশাটি এটিতে Numসংজ্ঞায়িত Prelude, এবং টিপলস এবং Floatসংজ্ঞায়িত করা হয় Prelude, সুতরাং এই তিনটি জিনিস কীভাবে কাজ করে সে সম্পর্কে সমস্ত কিছু সংজ্ঞায়িত হয় Prelude। সম্পূর্ণ ভিন্ন মডিউল আমদানি করলে কেন কিছু পরিবর্তন হবে? আদর্শভাবে এটি হবে না, তবে এতিম দৃষ্টান্তগুলি সেই স্বজ্ঞাতাকে ভঙ্গ করে।

(নোট করুন যে জিএইচসি অনাথ ঘটনার বিষয়ে সতর্ক করেছে - glossবিশেষত লেখকরা সেই সতর্কবাণীকে ছাড়িয়ে গেছে That এটি একটি লাল পতাকা উত্থাপন করা উচিত ছিল এবং ডকুমেন্টেশনে কমপক্ষে একটি সতর্কতা জাগানো উচিত ছিল।)

শ্রেণীর উদাহরণগুলি বিশ্বব্যাপী এবং লুকানো যায় না

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

আপনি আমদানি তালিকা ব্যবহার করতে পারবেন না দৃষ্টান্ত আমদানি এড়াতে । একইভাবে, আপনি যে মডিউলগুলি সংজ্ঞায়িত করেছেন তা থেকে রফতানির ঘটনা এড়াতে পারবেন না।

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

(যাইহোক, এই উত্তরটি যেমন প্রকাশিত হয়েছে , আপনি অনাথ দৃষ্টান্ত ব্যবহার করে কিছু ক্ষেত্রে বিশ্বব্যাপী দৃষ্টান্তকে ভেঙে ফেলতে পারেন !)

লাইব্রেরি প্রয়োগকারীদের জন্য কী

বাস্তবায়নের আগে দু'বার ভাবুন Num। আপনি fromIntegerসমস্যার আশপাশে কাজ করতে পারবেন না - সংজ্ঞায়িত করা এটি আরও ভাল fromInteger = error "not implemented"করে না । আপনার ব্যবহারকারীরা কি বিভ্রান্ত বা অবাক হবেন - বা আরও খারাপ, কখনই খেয়াল করবেন না their যদি তাদের পূর্ণসংখ্যার অক্ষরগুলি দুর্ঘটনাক্রমে আপনি যে ধরণের ইনস্ট্যান্ট করছেন সেটির জন্য অনুমান করা হয়? সরবরাহ করছে (*)এবং (+)সেই সমালোচনা-বিশেষত যদি আপনাকে এটি হ্যাক করতে হয়?

কনাল এলিয়টের vector-space(ধরণের ধরণের জন্য *) বা এডওয়ার্ড কেমেটের linear( ধরণের ধরণের জন্য ) লাইব্রেরিতে সংজ্ঞায়িত বিকল্প গাণিতিক অপারেটরগুলি ব্যবহার করার বিষয়ে বিবেচনা করুন * -> *। এই আমি নিজেই ঝোঁক।

ব্যবহার -Wall। এতিম দৃষ্টান্তগুলি প্রয়োগ করবেন না এবং অনাথ দৃষ্টান্তের সতর্কতাটি অক্ষম করবেন না।

পর্যায়ক্রমে, linearএবং আরও অনেক ভাল আচরণিত গ্রন্থাগারগুলির নেতৃত্ব অনুসরণ করুন এবং এথাম দৃষ্টান্তগুলি পৃথক মডিউলে .OrphanInstancesবা এর মধ্যে শেষ করুন .Instances। এবং অন্য কোনও মডিউল থেকে সেই মডিউলটি আমদানি করবেন না । তারপরে ব্যবহারকারীরা এতিমদের তারা চাইলে স্পষ্টভাবে আমদানি করতে পারেন।

যদি আপনি নিজেকে অনাথ সংজ্ঞায়িত করতে দেখেন তবে সম্ভব এবং যথাযথ হলে পরিবর্তে প্রবাহের রক্ষণাবেক্ষণকারীদের তাদের বাস্তবায়নের জন্য জিজ্ঞাসা করুন। আমি এতিম উদাহরণটি প্রায়শই লিখতাম Show a => Show (Identity a), যতক্ষণ না তারা এটিকে যুক্ত করে transformers। এমনকি আমি এটি সম্পর্কে একটি বাগ রিপোর্ট উত্থাপিত হতে পারে; মনে নেই।

গ্রাহক গ্রাহকদের জন্য কী করবেন do

আপনার কাছে অনেক বিকল্প নেই। লাইব্রেরি রক্ষণাবেক্ষণকারীদের কাছে - বিনয়ের সাথে এবং গঠনমূলকভাবে পৌঁছান। তাদের এই প্রশ্নের দিকে নির্দেশ করুন। সমস্যাযুক্ত এতিম লেখার জন্য তাদের কিছু বিশেষ কারণ থাকতে পারে বা তারা বুঝতে পারে না।

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

প্রতিশব্দের newtypeপরিবর্তে আপনার নিজস্ব সংজ্ঞা দিন typeযদি এটি যথেষ্ট গুরুত্বপূর্ণ হয়। আপনি পুরোপুরি নিশ্চিত হতে পারেন যে তাদের সাথে কেউ গণ্ডগোল করবে না।

যদি আপনার কোনও ওপেন-সোর্স লাইব্রেরি থেকে ঘন ঘন সমস্যা দেখা দেয় তবে আপনি অবশ্যই লাইব্রেরির নিজস্ব সংস্করণ তৈরি করতে পারেন তবে রক্ষণাবেক্ষণ দ্রুত মাথা ব্যথার কারণ হয়ে উঠতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.