سؤال

أجد نفسي أكتب الكثير من التعليمات البرمجية مثل

putStr "foo (bar 1) (bar 2) ="
print $ foo (bar 1) (bar 2)

المشكلة هي أن الرسالة المطبوعة يمكن أن تخرج عن المزامنة مع التعليمات البرمجية المنفذة الفعلية.الحل الواضح هو إنشاء هذا الرمز تلقائيا.

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

لا أحد يعرف كيف أود أن أذهب عن كتابة وظيفة أن يأخذ String ويولد رمز أعلاه منه?أعتقد أنه يجب أن يكون سهلا جدا ، لكن لم يتم توثيقه جيدا.

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

المحلول

يمكنك تحليل كود هاسكل باستخدام haskell-src-meta حزمة.وهنا مثال سريع كيف يمكن الجمع بين هذا مع قالب هاسكل.

{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.Meta

runShow = QuasiQuoter
    { quoteExp  = runShowQQ
    , quotePat  = undefined
    , quoteType = undefined
    , quoteDec  = undefined
    }

runShowQQ :: String -> Q Exp
runShowQQ s = do
    let s'          = s ++ " = "
        Right exp = parseExp s
        printExp  = appE [|print|] (return exp)
    infixApp [|putStr s'|] [|(>>)|] printExp

وكنت استخدامه مثل هذا

{-# LANGUAGE QuasiQuotes #-}

[runShow|foo (bar 1) (bar 2)|]

نصائح أخرى

قالب Haskell لا يوفر وسيلة واضحة لتحليل السلاسل التعسفية، لذلك ربما يكون الحل أبسط هو استخدام Preprocessor C.ومع ذلك، فإن المدمج في GHC لا يدعم التثقيف، لذلك نحتاج إلى اجتياز خيارات إضافية لاستخدام واحد "الحقيقي" بدلا من ذلك. giveacodicetagpre.

يمكنك بعد ذلك استخدامه مثل هذا: giveacodicetagpre.

هناك مثال على رمز Haskell الذي يشبه eval باستخدام GHC API هنا . / ص>

أوتش. أنا الفكر سيكون هذا سهلا، ولكن بقدر ما أستطيع أن أقول، إنه في الواقع المستحيل .

كنت أتوقع أن تكون هناك وظيفة تقوم بتشغيل سلسلة في تعبير، ولكن يبدو أن مثل هذه الوظائف موجودة. لا توجد وظيفة لتحميل مزيد من التعليمات البرمجية المصدر من القرص. لذلك يبدو أن هذه المهمة مستحيلة بالفعل! أنا مندهش جدا في ذلك.

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

كنت قد فكرت بميزة مثل هذا سيكون تافهة جميلة للتنفيذ. لذلك لا يمكن أن يعزى حقيقة أنه لم تنفذ إلا إلى واحد من شيئين:

  1. لا أحد يحتاج إليها في الواقع هذه الميزة. (حسنا، ما عدا لي، من الواضح.)

  2. ليس تافهة كما يبدو. (على سبيل المثال، ربما لمعرفة ما سياق تحليل التعبير هو fiddly بطريقة أو بأخرى؟)

يمكنك أيضا استخدام تفريغ الحزمة التي تمت كتابتها للتعامل مع حالة الاستخدام الدقيقة هذه:

{-# language QuasiQuotes #-}
import Debug.Dump

main = putStrLn [d| foo (bar 1) (bar 2) |]

foo = (+)
bar = (+1)

الذي يطبع: (foo (bar 1) (bar 2)) = 5

كما أنه يتعامل مع أكثر من تعبير مفصول بفواصل:

putStrLn [d| foo (bar 1) (bar 2), map bar [1, 2] |]

الذي يطبع: (foo (bar 1) (bar 2)) = 5 (map bar [1, 2]) = [2,3]

مكافأة:إذا كان لديك نيكس شل تثبيت (جزء من مدير حزمة نيكس) يمكنك حتى محاولة بها بسرعة مع هذا"بطانة واحدة":

$ nix-shell -p "nix-shell -p "haskellPackages.ghcWithPackages (p: [p.dump])" --run "echo '{-# language QuasiQuotes #-}; import Debug.Dump; foo = (+); bar = (+1); main = putStrLn [d| foo (bar 1) (bar 2), map bar [1, 2] |]' | runhaskell"

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