প্রথমত, আমি ডেটা.ভেক্টরকে দেখার পরামর্শ দিই , কিছু ক্ষেত্রে ডেটা.আরয়ের একটি ভাল বিকল্প ।
Array
এবং "সর্বাধিক পাথ সন্ধান করা" সম্পর্কে আমার জবাবVector
হিসাবে প্রমাণিত কিছু স্মৃতিচারণ মামলার জন্য আদর্শ । তবে কিছু সমস্যা কেবল কার্যকরী শৈলীতে প্রকাশ করা সহজ নয়। উদাহরণস্বরূপ, সমস্যা 28 মধ্যে প্রকল্প ইউলার একটি সর্পিল এর কর্ণ সংখ্যা summing জন্য আহ্বান জানাচ্ছে। অবশ্যই, এই সংখ্যার জন্য সূত্রটি খুঁজে পাওয়া খুব সহজ হওয়া উচিত, তবে সর্পিলটি তৈরি করা আরও চ্যালেঞ্জক।
ডেটা.আরে.এসটি একটি মিউটেটেবল অ্যারে প্রকার সরবরাহ করে। যাইহোক, টাইপ অবস্থা একটি জগাখিচুড়ি: এটা ব্যবহার বর্গ MArray ছাড়া তার পদ্ধতির প্রতি একক এক জমিদার করার runSTArray । সুতরাং, যদি না আপনি কোনও পরিবর্তনীয় অ্যারের ক্রিয়া থেকে অপরিবর্তনযোগ্য অ্যারে ফেরত দেওয়ার পরিকল্পনা না করেন, আপনাকে এক বা একাধিক ধরণের স্বাক্ষর যুক্ত করতে হবে:
import Control.Monad.ST
import Data.Array.ST
foo :: Int -> [Int]
foo n = runST $ do
a <- newArray (1,n) 123 :: ST s (STArray s Int Int) -- this type signature is required
sequence [readArray a i | i <- [1..n]]
main = print $ foo 5
তবুও, অ্যালার 28-তে আমার সমাধানটি বেশ সুন্দরভাবে বেরিয়ে এসেছিল এবং আমি ব্যবহার করেছি বলে এ জাতীয় স্বাক্ষরের প্রয়োজন হয় না runSTArray
।
ডেটা.ম্যাপকে "পরিবর্তনযোগ্য অ্যারে" হিসাবে ব্যবহার করা হচ্ছে
আপনি যদি কোনও মিউটেটেবল অ্যারে অ্যালগরিদম বাস্তবায়ন করতে চান তবে অন্য বিকল্পটি হ'ল ডেটা.ম্যাপ । আপনি যখন একটি অ্যারে ব্যবহার করেন, আপনার ধরণের ইচ্ছে মতো আপনার কোনও ফাংশন থাকে যা অ্যারের একক উপাদানকে পরিবর্তন করে:
writeArray :: Ix i => i -> e -> Array i e -> Array i e
দুর্ভাগ্যক্রমে, এটির জন্য পুরো অ্যারে অনুলিপি করা দরকার, যদি না সম্ভব হয় যখন সম্ভব হয় তা এড়াতে কোনও অনুলিপি কৌশল প্রয়োগ না করে implementation
সুসংবাদটি হ'ল, Data.Map
এর মতো একটি ফাংশন রয়েছে, sertোকান :
insert :: Ord k => k -> a -> Map k a -> Map k a
কারণ Map
অভ্যন্তরীণভাবে ভারসাম্য বাইনারি গাছ হিসাবে প্রয়োগ করা হয়, insert
কেবলমাত্র ও (লগ এন) সময় এবং স্থান নেয় এবং মূল অনুলিপি সংরক্ষণ করে। সুতরাং, Map
কেবলমাত্র কিছুটা দক্ষ "মিউটেবল অ্যারে" সরবরাহ করে না যা কার্যকরী প্রোগ্রামিং মডেলের সাথে সামঞ্জস্যপূর্ণ, তবে এটি যদি আপনি চান তবে আপনাকে "সময়মতো ফিরে যেতে" দেয়।
ডেটা.ম্যাপ ব্যবহার করে অুলার 28 এর একটি সমাধান এখানে রয়েছে:
{-# LANGUAGE BangPatterns #-}
import Data.Map hiding (map)
import Data.List (intercalate, foldl')
data Spiral = Spiral Int (Map (Int,Int) Int)
build :: Int -> [(Int,Int)] -> Map (Int,Int) Int
build size = snd . foldl' move ((start,start,1), empty) where
start = (size-1) `div` 2
move ((!x,!y,!n), !m) (dx,dy) = ((x+dx,y+dy,n+1), insert (x,y) n m)
spiral :: Int -> Spiral
spiral size
| size < 1 = error "spiral: size < 1"
| otherwise = Spiral size (build size moves) where
right = (1,0)
down = (0,1)
left = (-1,0)
up = (0,-1)
over n = replicate n up ++ replicate (n+1) right
under n = replicate n down ++ replicate (n+1) left
moves = concat $ take size $ zipWith ($) (cycle [over, under]) [0..]
spiralSize :: Spiral -> Int
spiralSize (Spiral s m) = s
printSpiral :: Spiral -> IO ()
printSpiral (Spiral s m) = do
let items = [[m ! (i,j) | j <- [0..s-1]] | i <- [0..s-1]]
mapM_ (putStrLn . intercalate "\t" . map show) items
sumDiagonals :: Spiral -> Int
sumDiagonals (Spiral s m) =
let total = sum [m ! (i,i) + m ! (s-i-1, i) | i <- [0..s-1]]
in total-1 -- subtract 1 to undo counting the middle twice
main = print $ sumDiagonals $ spiral 1001
ঠাণ্ডা নিদর্শনগুলি সঞ্চয়ের আইটেমগুলি (কার্সার, সংখ্যা এবং মানচিত্র) একেবারে শেষ অবধি ব্যবহার না করায় স্ট্যাকের ওভারফ্লো প্রতিরোধ করে। বেশিরভাগ কোড গল্ফগুলির জন্য, এই বিধানের প্রয়োজনের জন্য ইনপুট কেসগুলি এত বড় হওয়া উচিত নয়।