من أي الأشياء التي يجب أن أعتني بها إذا كنت أستخدم نوعًا غير مصنوع (مثل int#) في Haskell / GHC؟

StackOverflow https://stackoverflow.com/questions/3641573

سؤال

أحاول كتابة برنامج نصي صغير يقوم بتوصيف وينفذ رمز Brainfuck ، لفهم خيارات GHC للتحسين ، أحاول تحسين الكود من أجل أن أكون أسرع قليلاً وفهم ما يجري هناك.

على الأجزاء ، يوجد تمثيل داخلي لـ BF-Code ، أستخدم نوع بيانات خاص لهذا الغرض. فيما يلي رمز Sourcecode ، وشملت وظيفتين تقومان بالتحويلات:

data BFinstruction
  = AdjustValue Int
  | MovePointer Int
  | GetChar
  | PutChar
  | Loop BFcode
  deriving (Eq)

type BFcode = [BFinstruction]

unsafeCompileBrainfuck :: String -> BFcode
unsafeCompileBrainfuck = fst . parse [] where
  -- arguments: input string, built code; output: output code, rest of input
  parse :: BFcode -> String -> (BFcode,String)
  parse c ('+':s) = parse (AdjustValue   1 :c) s
  parse c ('-':s) = parse (AdjustValue (-1):c) s
  parse c ('>':s) = parse (MovePointer   1 :c) s
  parse c ('<':s) = parse (MovePointer (-1):c) s
  parse c ('.':s) = parse (PutChar         :c) s
  parse c (',':s) = parse (GetChar         :c) s
  parse c (']':s) = (reverse c, s)
  parse c ('[':s) = parse (Loop l          :c) s' where (l,s') = parse [] s
  parse c []      = (reverse c ,"")
  parse c ( _ :s) = parse                   c  s

simplifyBrainfuck :: BFcode -> BFcode
simplifyBrainfuck ((AdjustValue x):(AdjustValue y):zs) = if x + y /= 0
  then simplifyBrainfuck (AdjustValue (x + y):zs)
  else simplifyBrainfuck zs
simplifyBrainfuck ((MovePointer x):(MovePointer y):zs) = if x + y /= 0
  then simplifyBrainfuck (MovePointer (x + y):zs)
  else simplifyBrainfuck zs
simplifyBrainfuck (x                              :zs) = x: simplifyBrainfuck zs
simplifyBrainfuck []                                   = []

الفكرة هي أنه سيتم قراءة الكود من بعض الإدخال (السلسلة) ، وتم تبسيطها وتبسيطها بواسطة الكود أعلاه ثم تنفيذها بواسطة بعض الوظائف الأخرى. (من المفترض ، أن المدخلات صالحة).

من أجل تحسين هذا المثال ، حاولت إلغاء صناديق المعلمات int من MovePointer و AdjustValue المنشئون عن طريق القيام بمثل هذا:

data BFinstruction -- BangPatterns
  = AdjustValue {-# UNPACK #-} !Int
  | MovePointer {-# UNPACK #-} !Int
  | GetChar
  | PutChar
  | Loop BFcode
  deriving (Eq)

هذا سيحول المعبأة Int اكتب في خام ، خام Int# النوع ، وهو تفاصيل تنفيذ من GHC. كما قرأت ، هذا الخيار جيد فقط في حالات قليلة ، لذلك أريد أن أسأل ، الأشياء التي يجب أن أولي اهتمامًا بها إذا أردت أداء هذا النوع من التحسين. هدفي هو السماح بتنفيذ BF -Code باستخدام فوائد Haskell - الكسل (أريد أن أروي ، أنه قد يتم الاحتفاظ بالرمز فقط حسب الحاجة في الذاكرة) والسرقة.

هل كانت مفيدة؟

المحلول

هذا يبدو حقًا وكأنه تحسين سابق لأوانه بالنسبة لي. تفريغه مفيد في الغالب عندما يكون لديك عدد كبير جدًا من BFInstructionS يجلس. أشك في أنه سيكون لديك ما يكفي من الرمز Brainf ** K لجعله يستحق العناء. وأنا أتفق مع جيان ، يجب أن يكون الأمر بسيطًا بما يكفي للاختبار ، لذا فعل ذلك أولاً.

في أي حال ، فإن الشيء الذي يجب أن تكون على دراية به مع قيم تفريغه هو أنك لا تريد أن يضطر المترجم إلى إعادة صندوقها. يجب أن تكون على ما يرام مع العمليات العددية ، ولكن بخلاف ذلك ، يجب عليك أن تنظر بعناية في الوظائف التي تستخدمها لمعرفة ما إذا كنت تستخدم القيم غير المعبأة كوسيطة غير متجانسة. الطريقة الوحيدة للتأكد من أن النظر إلى النواة ، أو ملفات الواجهة ، لمعرفة المعلمات الصارمة وأيها ليست كذلك. كما هو الحال دائمًا ، تأكد من تجميعها على الأقل "-o".

نصائح أخرى

هل هذا ضروري حقًا؟ هل تواجه مشاكل في الأداء مع هذا الرمز الذي تعتقد أنه نتيجة للقيم المعبأة؟ إذا لم يكن كذلك ، لا تهتم.

إذا كنت تعتقد أن هذا هو الحال ، إذن هذه الصفحة في دليل GHC يبدو أن يوفر القيود اللازمة في تنسيق قائمة مريحة.

يبدو أن النقاط الرئيسية هي أن أي نوع من التفاعل بين الوظائف أو الأسماء المتعددة الأشكال والأنواع غير المربوطة التي لم يتم رفضها من قبل المترجم يمكن أن يؤدي إلى تسرب مساحة سيئة. أيضًا ، دون أن أجربه ، أظن أنك لن تحصل على استثناءات في حالة الفائض ، على سبيل المثال ، لذلك من المفترض أنه يجب عليك اكتشاف هذا النوع من الأشياء بنفسك. يمكن أن يتحقق اختبار بسيط إذا كان هذا هو الحال بالفعل أم لا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top