হাসেল মেমরি দক্ষতা - ভাল পদ্ধতির কোনটি?


11

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

ব্যাকরণগুলিতে ডানহাতে পাশের 4 টি প্রোডাকশন বা একটি টার্মিনাল সহ নন-টার্মিনাল রয়েছে। সমতা চেক এবং ব্যাকরণ হ্রাসকরণের জন্য আমাদের প্রোডাকশনের নাম প্রয়োজন।

প্রথম:

-- | Type synonym for non-terminal symbols
type NonTerminal = String

-- | Data type for the right hand side of a production
data RightHandSide = DownStep NonTerminal NonTerminal NonTerminal NonTerminal | Terminal Int

-- | Data type for a set of productions
type ProductionMap = Map NonTerminal RightHandSide

data MatrixGrammar = MatrixGrammar {
    -- the start symbol
    startSymbol :: NonTerminal,
    -- productions
    productions :: ProductionMap    
    } 

এখানে আমাদের রাইটহ্যান্ডসাইড ডেটা পরবর্তী স্ট্রাকশনগুলি নির্ধারণের জন্য কেবল স্ট্রিংয়ের নাম সংরক্ষণ করে এবং যা আমরা এখানে জানি না তা হ্যাসেল কীভাবে এই স্ট্রিংগুলি সংরক্ষণ করে। উদাহরণস্বরূপ [[0, 0], [0, 0]] ম্যাট্রিক্সের 2 টি প্রোডাকশন রয়েছে:

a = Terminal 0
aString = "A"
b = DownStep aString aString aString aString
bString = "B"
productions = Map.FromList [(aString, a), (bString, b)]

সুতরাং এখানে প্রশ্নটি হল স্ট্রিং "এ" সত্যিই কতবার সংরক্ষণ হয়? একবার এস্ট্রিং-এ, 4 বার বি এবং একবার প্রযোজনায় বা একবার কেবল স্ট্রিংয়ে এবং অন্যেরা কেবল "সস্তা" রেফারেন্স রাখেন?

দ্বিতীয়:

data Production = NonTerminal String Production Production Production Production
                | Terminal String Int 

type ProductionMap = Map String Production

এখানে "টার্মিনাল" শব্দটি কিছুটা বিভ্রান্তিকর কারণ এর প্রকৃতপক্ষে উত্পাদনে ডান হাতের মতো টার্মিনাল রয়েছে। একই ম্যাট্রিক্স:

a = Terminal "A" 0
b = NonTerminal "B" a a a a
productions = Map.fromList [("A", a), ("B", b)]

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

সুতরাং আসুন আমরা আমাদের প্রায় 1000 প্রযোজনার সাথে একটি ব্যাকরণ রাখতে পারি বলে মনে করি। কোন পদ্ধতির কম স্মৃতি গ্রাস করবে?

অবশেষে হাস্কেলের পূর্ণসংখ্যা সম্পর্কে একটি প্রশ্ন: বর্তমানে আমরা স্ট্রিং হিসাবে নাম রাখার পরিকল্পনা করছি। তবে আমরা সহজেই পূর্ণসংখ্যার নামগুলিতে স্যুইচ করতে পারি কারণ 1000 প্রযোজনার সাথে আমাদের আরও 4 টি বর্ণের নাম থাকবে (যা আমি মনে করি 32 বিট?) হাসেল কীভাবে এটি পরিচালনা করে। একটি INT সর্বদা 32 বিট এবং পূর্ণসংখ্যার মেমরিটির সত্যিকার অর্থে প্রয়োজনীয় বরাদ্দ করে?

আমি এর মাধ্যমে আরও পড়লাম: হাস্কেলের মান / রেফারেন্স শব্দার্থ আবিষ্কারের পরীক্ষা-নিরীক্ষা - তবে আমাদের জন্য এটি ঠিক কী বোঝায় তা বুঝতে পারি না - আমি একজন আবশ্যক জাভা সন্তানের পক্ষে আরও ভাল কর্মক্ষম প্রোগ্রামার: পি

উত্তর:


7

আপনি নিজের ম্যাট্রিক্স ব্যাকরণকে এডিটিতে বিস্তৃত করতে পারেন সামান্য কৌশল নিয়ে সঠিক ভাগ করে নেওয়ার সাথে:

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}

import Data.Map
import Data.Foldable
import Data.Functor
import Data.Traversable

-- | Type synonym for non-terminal symbols
type NonTerminal = String

-- | Data type for the right hand side of a production
data RHS a = DownStep NonTerminal NonTerminal NonTerminal NonTerminal | Terminal a
  deriving (Eq,Ord,Show,Read,Functor, Foldable, Traversable)

data G a = G NonTerminal (Map NonTerminal (RHS a))
  deriving (Eq,Ord,Show,Read,Functor)

data M a = Q (M a) (M a) (M a) (M a) | T a
  deriving (Functor, Foldable, Traversable)

tabulate :: G a -> M a
tabulate (G s pm) = loeb (expand <$> pm) ! s where
  expand (DownStep a11 a12 a21 a22) m = Q (m!a11) (m!a12) (m!a21) (m!a22)
  expand (Terminal a)               _ = T a

loeb :: Functor f => f (f b -> b) -> f b
loeb x = xs where xs = fmap ($xs) x

এখানে আমি আপনার ব্যাকরণকে কেবলমাত্র ইনট নয়, কোনও ডাটা টাইপের জন্য অনুমতি দেওয়ার জন্য সাধারণকরণ করেছি tabulateএবং ব্যাকরণটি গ্রহণ করব এবং এটি নিজেই এটি ব্যবহার করে ভাঁজ করে এটি প্রসারিত করব loeb

loebড্যান পিপোনি একটি নিবন্ধে বর্ণনা করা হয়

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

loebনিষ্পাপ সম্প্রসারণের বিপরীতে, ব্যবহার করে আমাকে 'গিঁট বেঁধে' দিতে এবং একই অ-টার্মিনালের সমস্ত ঘটনার জন্য ধন্যবাদ জানাতে পারি।

আপনি যদি এই সমস্তটির তত্ত্বটিতে আরও ডুবতে চান তবে আমরা দেখতে পাই এটি RHSএকটি বেস ফান্টারে পরিণত হতে পারে:

data RHS t nt = Q nt nt nt nt | L t

এবং তারপরে আমার এম টাইপ এটির নির্দিষ্ট পয়েন্ট Functor

M a ~ Mu (RHS a)

যখন G aএকটি নির্বাচিত স্ট্রিং এবং স্ট্রিং থেকে শুরু করে একটি মানচিত্র থাকে (RHS String a)

আমরা তখন প্রসারিত করতে Gমধ্যে Mপ্রসারিত স্ট্রিং প্রখর রৌদ্রে একটি মানচিত্র মধ্যে এন্ট্রি আপ অনুসন্ধান দ্বারা।

এটি data-reifyপ্যাকেজটিতে যা করা হয় তার দ্বৈত বিষয় যা এই ধরণের বেস ফ্যাঙ্ক্টর নিতে পারে Mএবং Gএটি থেকে আপনার মতো নৈতিক সমতুল্য পুনরুদ্ধার করতে পারে। তারা নন-টার্মিনাল নামের জন্য আলাদা ধরণের ব্যবহার করে, যা মূলত কেবল একটি Int

data Graph e = Graph [(Unique, e Unique)] Unique

এবং একটি সংযোগকারী সরবরাহ করুন

reifyGraph :: MuRef s => s -> IO (Graph (DeRef s))

যা স্বেচ্ছাসেবীর ম্যাট্রিক্স থেকে গ্রাফ (ম্যাট্রিক্সগ্র্যামার) পেতে উপরের ডেটা টাইপগুলিতে উপযুক্ত উদাহরণ সহ ব্যবহার করা যেতে পারে। এটি অভিন্ন কিন্তু পৃথকভাবে সঞ্চিত চতুর্ভুজগুলির নকল করবে না, তবে এটি মূল গ্রাফে উপস্থিত সমস্ত ভাগ ভাগ করে নেবে।


8

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

আমি মনে করি আপনি উপরের থেকে অনুমান করতে পারেন যে স্ট্রিং খুব কমপ্যাক্ট বা অন্যথায় দক্ষ উপস্থাপনা নয়। স্ট্রিংগুলির জন্য সাধারণ বিকল্প উপস্থাপনার মধ্যে ডেটা.টেক্সট এবং ডেটা.বাইটস্ট্রিং সরবরাহ করে include

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

ইন্ট যতদূর যায় এটি একটি নির্দিষ্ট-প্রস্থের প্রকারের ধরণের, তবে মানগুলি ধরে রাখার জন্য এটি যথেষ্ট প্রশস্ত হওয়া আবশ্যক ব্যতীত এটি কত প্রশস্ত তার কোনও গ্যারান্টি নেই [-2 ^ 29 .. 2 ^ 29-1]। এটি প্রস্তাব দেয় এটি কমপক্ষে 32 বিট, তবে 64 বিট থাকার বিষয়টি অস্বীকার করে না। তথ্য.এর আরও কিছু নির্দিষ্ট প্রকার রয়েছে, ইনট 8-ইন্ট 64, যা আপনার নির্দিষ্ট প্রস্থের প্রয়োজন হলে আপনি ব্যবহার করতে পারেন।

তথ্য যুক্ত করতে সম্পাদনা করুন

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

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

ইন্টার্নিং করে এমন একটি লাইব্রেরির জন্য আপনি https://github.com/ekmett/intern/ ব্যবহার করতে পারেন

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

polyConstructor :: Integral a => a -> MyType a
int16Constructor :: Int16 -> MyType Int16
int32Constructor :: Int32 -> MyType Int32

int16Constructor = polyConstructor
int32Constructor = polyConstructor

সম্পাদনা করুন : ইন্টার্নিং সম্পর্কে আরও তথ্য

আপনি যদি কেবল ইন্টার্ন স্ট্রিং করতে চান তবে আপনি একটি নতুন টাইপ তৈরি করতে পারেন যা একটি স্ট্রিং (পছন্দমত কোনও পাঠ্য বা বাইটস্ট্রিং) এবং একটি ছোট পূর্ণসংখ্যাকে একসাথে আবদ্ধ করতে পারে।

data InternedString = { id :: Int32, str :: Text }
instance Eq InternedString where
    {x, _ } == {y, _ }  =  x == y

intern :: MonadIO m => Text -> m InternedString

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

এখন আপনি পূর্ণসংখ্যার আইডির ভিত্তিতে একটি দ্রুত তুলনা পান এবং প্রতিটি অনন্য স্ট্রিংয়ের কেবল একটি অনুলিপি পান।

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


আপনার উত্তরের জন্য এতক্ষণ ধন্যবাদ রানটাইম সময় আমাদের কোন int আকার ব্যবহার করা উচিত তা নির্ধারণ করা সম্ভব? আমি আশা করি অন্য অনুলিপিগুলির সাথে অন্য কেউ সমস্যাটির জন্য কিছু ইনপুট দিতে পারে :)
ডেনিস আইচ

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

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