سؤال

غالبًا ما أجد هذا النمط في كود هاسكل:

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

...

doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
  opt <- readMVar options
  doSomething' where ...

في الأساس، يكون لدى المرء سجل من الخيارات أو شيء مشابه، والذي يتم تعيينه في البداية في بداية البرنامج.بما أن المبرمج كسول فلا يريد أن يحمل الملف options سجل في جميع أنحاء البرنامج.فهو يحدد MVar للحفاظ عليه - تم تحديده من خلال الاستخدام القبيح لـ unsafePerformIO.يضمن المبرمج أن يتم ضبط الحالة مرة واحدة فقط وقبل إجراء أي عملية.الآن يجب استخدام كل جزء من البرنامج unsafePerformIO مرة أخرى، فقط لاستخراج الخيارات.

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

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

المحلول

إذا كنت تستخدم MVar لضبط الإعدادات أو شيء مشابه، فلماذا لا تجرب Reader monad؟

foo :: ReaderT OptionRecord IO ()
foo = do
    options <- ask
    fireMissiles

main = runReaderT foo (OptionRecord "foo")

(والقارئ العادي إذا كنت لا تحتاج إلى IO :P)

نصائح أخرى

أولئك الذين سيتاجرون بالشفافية المرجعية الأساسية لقليل من الراحة المؤقتة لا يستحقون أي نقرة ولا راحة.

هذه فكرة سيئة.الكود الذي تجده فيه هو كود سيء.*

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

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

استخدم المعلمات الضمنية.إنها أقل وزنًا قليلاً من كل وظيفة Reader أو ReaderT في نوعه.يجب عليك تغيير توقيعات النوع لوظائفك، ولكن أعتقد أنه يمكن كتابة مثل هذا التغيير.(ستكون ميزة رائعة لـ Haskell IDE.)

هناك سبب مهم لعدم استخدام هذا النمط.على حد علمي، في

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

هاسكل لا يعطي أي ضمانات لذلك options سيتم التقييم مرة واحدة فقط.منذ نتيجة option هي قيمة خالصة، ويمكن حفظها وإعادة استخدامها، ولكن يمكن أيضًا إعادة حسابها لكل مكالمة (أي.مضمن) ويجب ألا يتغير معنى البرنامج (خلافًا لحالتك).

إذا كنت لا تزال تقرر استخدام هذا النمط، تأكد من إضافة {-# NOINLINE options #-}, وإلا فقد يتم تضمينه وسيفشل برنامجك!(وبهذا فإننا نتخلص من الضمانات التي توفرها اللغة ونظام الكتابة ونعتمد فقط على تنفيذ مترجم معين.)

تمت مناقشة هذا الموضوع على نطاق واسع وتم تلخيص الحلول الممكنة بشكل جيد على Haskell Wiki في أعلى حالة قابلة للتغيير.ليس من الممكن حاليًا تجريد هذا النمط بأمان دون دعم إضافي للمترجم.

غالبًا ما أجد هذا النمط في كود هاسكل:

قراءة رمز مختلف.

نظرًا لأن المبرمج كسول، فهو لا يريد أن يحمل سجل الخيارات في جميع أنحاء البرنامج.لقد قام بتعريف MVar للاحتفاظ به - تم تحديده من خلال الاستخدام القبيح لـ unsafePerformIO.يضمن المبرمج أن يتم ضبط الحالة مرة واحدة فقط وقبل إجراء أي عملية.الآن يجب على كل جزء من البرنامج استخدام unsafePerformIO مرة أخرى، فقط لاستخراج الخيارات.

يبدو هذا بالضبط ما ينجزه القارئ الأحادي، باستثناء أن القارئ الأحادي يفعل ذلك بطريقة آمنة.بدلاً من التكيف مع كسلك، ما عليك سوى كتابة كود فعلي جيد.

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