আমি এমন একটি সমাধান নিয়ে এসেছি যা হাস্কেল টাইপ সিস্টেম ব্যবহার করে। মান স্তরের সমস্যার বিদ্যমান সমাধানের জন্য আমি কিছুটা গুগল করেছিলাম , এটিকে কিছুটা পরিবর্তন করেছি, এবং তারপরে এটিকে টাইপ স্তরে তুলে নিয়েছি । এটি অনেকটা নতুন করে নিয়েছিল। আমারও একগুচ্ছ জিএইচসি এক্সটেনশান সক্ষম করতে হয়েছিল।
প্রথমত, যেহেতু টাইপ স্তরে পূর্ণসংখ্যার অনুমতি দেওয়া হয় না, তাই প্রাকৃতিক সংখ্যাগুলি পুনরায় পুনরায় উদ্ভাবন করা দরকার, টাইপ হিসাবে:
data Zero -- type that represents zero
data S n -- type constructor that constructs the successor of another natural number
-- Some numbers shortcuts
type One = S Zero
type Two = S One
type Three = S Two
type Four = S Three
type Five = S Four
type Six = S Five
type Seven = S Six
type Eight = S Seven
আমি যে অ্যালগরিদমকে মানিয়ে নিয়েছি সেগুলি প্রাকৃতিকগুলিতে সংযোজন এবং বিয়োগগুলি করে, তাই আমাকে এগুলিও পুনরায় উদ্ভাবন করতে হয়েছিল। টাইপ স্তরের কার্যকারিতা সংজ্ঞা দেওয়া হয় টাইপ শ্রেণীর অবলম্বনে। একাধিক প্যারামিটার ধরণের শ্রেণি এবং কার্যকরী নির্ভরতাগুলির জন্য এটিগুলির জন্য এক্সটেনশানগুলির প্রয়োজন। প্রকারের ক্লাসগুলি "মানগুলি ফেরত" দিতে পারে না, সুতরাং আমরা তার জন্য একটি অতিরিক্ত প্যারামিটার ব্যবহার করি, PROLOG এর অনুরূপ।
class Add a b r | a b -> r -- last param is the result
instance Add Zero b b -- 0 + b = b
instance (Add a b r) => Add (S a) b (S r) -- S(a) + b = S(a + b)
class Sub a b r | a b -> r
instance Sub a Zero a -- a - 0 = a
instance (Sub a b r) => Sub (S a) (S b) r -- S(a) - S(b) = a - b
পুনরাবৃত্তি শ্রেণিবদ্ধকরণের সাথে প্রয়োগ করা হয়, সুতরাং বাক্যবিন্যাসটি কিছুটা পিছনে দেখায়।
পরবর্তী বুলিয়ান ছিল:
data True -- type that represents truth
data False -- type that represents falsehood
এবং অসমতার তুলনা করার জন্য একটি ফাংশন:
class NotEq a b r | a b -> r
instance NotEq Zero Zero False -- 0 /= 0 = False
instance NotEq (S a) Zero True -- S(a) /= 0 = True
instance NotEq Zero (S a) True -- 0 /= S(a) = True
instance (NotEq a b r) => NotEq (S a) (S b) r -- S(a) /= S(b) = a /= b
এবং তালিকা ...
data Nil
data h ::: t
infixr 0 :::
class Append xs ys r | xs ys -> r
instance Append Nil ys ys -- [] ++ _ = []
instance (Append xs ys rec) => Append (x ::: xs) ys (x ::: rec) -- (x:xs) ++ ys = x:(xs ++ ys)
class Concat xs r | xs -> r
instance Concat Nil Nil -- concat [] = []
instance (Concat xs rec, Append x rec r) => Concat (x ::: xs) r -- concat (x:xs) = x ++ concat xs
class And l r | l -> r
instance And Nil True -- and [] = True
instance And (False ::: t) False -- and (False:_) = False
instance (And t r) => And (True ::: t) r -- and (True:t) = and t
if
টাইপ স্তরেও নিখোঁজ রয়েছে ...
class Cond c t e r | c t e -> r
instance Cond True t e t -- cond True t _ = t
instance Cond False t e e -- cond False _ e = e
এবং এটির সাথে সাথে, আমি ব্যবহৃত সমস্ত সহায়ক যন্ত্রপাতি ছিল। সমস্যাটি নিজেই সমাধান করার সময়!
কোনও বিদ্যমান বোর্ডে রানী যুক্ত করা ভাল কিনা তা পরীক্ষা করার জন্য একটি ফাংশন দিয়ে শুরু করা:
-- Testing if it's safe to add a queen
class Safe x b n r | x b n -> r
instance Safe x Nil n True -- safe x [] n = True
instance (Safe x y (S n) rec,
Add c n cpn, Sub c n cmn,
NotEq x c c1, NotEq x cpn c2, NotEq x cmn c3,
And (c1 ::: c2 ::: c3 ::: rec ::: Nil) r) => Safe x (c ::: y) n r
-- safe x (c:y) n = and [ x /= c , x /= c + n , x /= c - n , safe x y (n+1)]
মধ্যবর্তী ফলাফল পেতে শ্রেণিবদ্ধকরণের ব্যবহার লক্ষ করুন। যেহেতু রিটার্ন মানগুলি একটি অতিরিক্ত প্যারামিটার হয়, আমরা কেবল একে অপরের কাছ থেকে সরাসরি দৃ .়তাগুলি কল করতে পারি না। আবার আপনি যদি PROLOG ব্যবহার করেন তবে এই স্টাইলটি কিছুটা পরিচিত হতে পারে।
ল্যাম্বডাসের প্রয়োজনীয়তা অপসারণ করার জন্য আমি কয়েকটি পরিবর্তন করার পরে (যা আমি প্রয়োগ করতে পারতাম, তবে আমি অন্য একদিনের জন্য চলে যাবার সিদ্ধান্ত নিয়েছিলাম), এটির মূল সমাধানটি দেখে মনে হয়েছিল:
queens 0 = [[]]
-- The original used the list monad. I "unrolled" bind into concat & map.
queens n = concat $ map f $ queens (n-1)
g y x = if safe x y 1 then [x:y] else []
f y = concat $ map (g y) [1..8]
map
একটি উচ্চতর ক্রম ফাংশন। আমি ভেবেছিলাম উচ্চতর অর্ডার মেটা-ফাংশনগুলি প্রয়োগ করা খুব বেশি ঝামেলা হবে (আবার ল্যাম্বডাস) সুতরাং আমি কেবল একটি সহজ সমাধান নিয়ে চলেছি: যেহেতু আমি জানি যে কী ফাংশন ম্যাপ করা হবে map
, তাই আমি প্রতিটিটির জন্য বিশেষ সংস্করণগুলি প্রয়োগ করতে পারি , যাতে সেগুলি না হয় উচ্চতর আদেশ ক্রিয়াকলাপ।
-- Auxiliary meta-functions
class G y x r | y x -> r
instance (Safe x y One s, Cond s ((x ::: y) ::: Nil) Nil r) => G y x r
class MapG y l r | y l -> r
instance MapG y Nil Nil
instance (MapG y xs rec, G y x g) => MapG y (x ::: xs) (g ::: rec)
-- Shortcut for [1..8]
type OneToEight = One ::: Two ::: Three ::: Four ::: Five ::: Six ::: Seven ::: Eight ::: Nil
class F y r | y -> r
instance (MapG y OneToEight m, Concat m r) => F y r -- f y = concat $ map (g y) [1..8]
class MapF l r | l -> r
instance MapF Nil Nil
instance (MapF xs rec, F x f) => MapF (x ::: xs) (f ::: rec)
এবং শেষ মেটা-ফাংশনটি এখনই লেখা যেতে পারে:
class Queens n r | n -> r
instance Queens Zero (Nil ::: Nil)
instance (Queens n rec, MapF rec m, Concat m r) => Queens (S n) r
বাকিগুলি হ'ল সমাধানগুলি কার্যকর করার জন্য টাইপ-চেকিং মেশিনারিটিকে কক্সবাজারে চালিত করার জন্য একরকম ড্রাইভার।
-- dummy value of type Eight
eight = undefined :: Eight
-- dummy function that asserts the Queens class
queens :: Queens n r => n -> r
queens = const undefined
এই মেটা-প্রোগ্রামটি টাইপ চেকারে চালিত হওয়ার কথা, সুতরাং কেউ গুলি চালিয়ে ghci
প্রকারটি জানতে চাইতে পারে queens eight
:
> :t queens eight
এটি বরং দ্রুত ডিফল্ট পুনরাবৃত্তি সীমা অতিক্রম করবে (এটি একটি ম্যাসেজ 20)। এই সীমাটি বাড়ানোর জন্য, আমাদের বিকল্পটির ghci
সাথে আবেদন করতে হবে -fcontext-stack=N
, যেখানে N
পছন্দসই স্ট্যাকের গভীরতা রয়েছে (এন = 1000 এবং পনের মিনিটই যথেষ্ট নয়)। আমি এই রানটি এখনও সম্পূর্ণ করতে দেখিনি, কারণ এটি অনেক দীর্ঘ সময় নেয় তবে আমি চালিয়ে যেতে পেরেছি queens four
।
আছে একটি পুরো প্রোগ্রাম চমত্কার ফলাফলের ধরনের মুদ্রণের জন্য কিছু যন্ত্রপাতি দিয়ে ideone উপর, কিন্তু এর queens two
সীমা মাত্রাধিক ছাড়াই এটিকে চালাতে পারবেন :(