سؤال

لدي هذه الوظيفة البسيطة جدًا

import qualified Data.ByteString.Lazy as B

getJson :: IO B.ByteString
getJson = B.readFile jsonFile

readJFile :: IO (Maybe Response)
readJFile =  parsing >>= (\d ->
             case d of
                 Left err -> return Nothing
                 Right ps -> return (Just ps))
    where parsing = fmap eitherDecode getJson :: IO (Either String Response)

أين jsonFile هو مسار إلى ملف موجود على محرك الأقراص الثابتة الخاص بي (عذرًا على عدم وجود تدوين، لكنني وجدت هذا أكثر وضوحًا للعمل معه)

سؤالي هو؛هل هناك طريقة بالنسبة لي للتخلي عن IO جزء حتى أتمكن من العمل مع bytesting وحدها؟

أعلم أنه يمكنك مطابقة النمط مع بعض الأحاديات مثل Either و Maybe للحصول على قيمهم، ولكن هل يمكنك أن تفعل شيئا مماثلا مع IO?

أو بصوت مختلف:هل هناك طريقة بالنسبة لي لجعل readJFile يعود Maybe Response بدون IO؟

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

المحلول

للتوسع في تعليقاتي، إليك كيف يمكنك القيام بذلك:

giveacodicetagpre.

في النهاية، يمكنك الجمع بين كل شيء في إجراء IO مرة أخرى:

giveacodicetagpre.

نصائح أخرى

لن تحتاج أبدًا إلى "سحب موناد" عبر أي وظيفة، إلا إذا كانت جميعها تحتاج إلى إجراء عملية IO فعليًا.فقط ارفع السلسلة بأكملها إلى الموناد fmap (أو liftM / liftM2 / ...).

على سبيل المثال،

f1 :: B.ByteString -> K
f2 :: K -> I
f3 :: K -> J
f4 :: I -> J -> M

ومن المفترض أن يكون الأمر برمته هكذا

m :: M
m = let k = "f1 getJson"
    in f4 (f2 k) (f3 k)

يمكنك القيام بذلك ببساطة

m = fmap (\b -> let k = f1 b
                in f4 (f2 k) (f3 k) )
    getJson

بالمناسبة، قد يبدو هذا أجمل مع do الرموز:

m = do
  b <- getJson
  return $ let k = f1 b
           in f4 (f2 k) (f3 k)

فيما يتعلق بك تحرير والسؤال

هل هناك طريقة بالنسبة لي لجعل readJFile يعود Maybe Response بدون ال IO?

لا, ، هذا لا يمكن أن ينجح، لأنه readJFile لا حاجة للقيام IO.لا توجد وسيلة للهروب من IO موناد إذن، هذا هو بيت القصيد من ذلك!(حسنا، هناك unsafePerformIO كما يقول ريكاردو، ولكن هذا بالتأكيد ليس تطبيقًا صالحًا لذلك.)

إذا كان الأمر يتعلق بصعوبة التفريغ Maybe القيم في IO الموناد، والتوقيعات التي تحتوي على أقواس، قد ترغب في إلقاء نظرة على MaybeT محول.

readJFile' :: MaybeT IO Response
readJFile' = do
   b <- liftIO getJson
   case eitherDecode b of
     Left err -> mzero
     Right ps -> return ps

بشكل عام، نعم، هناك طريقة.يرافقه الكثير من "لكن"، ولكن هناك.أنت تسأل عما يسمى عملية إدخال/إخراج غير آمنة: System.IO.Unsafe.يتم استخدامه لكتابة الأغلفة عند الاتصال بالمكتبات الخارجية عادةً، وهو ليس شيئًا يمكن اللجوء إليه في كود هاسكل العادي.

في الأساس، يمكنك الاتصال unsafePerformIO :: IO a -> a الذي يفعل بالضبط ما تريد، فإنه يزيل IO جزء ويعطيك قيمة ملفوفة مرة أخرى من النوع a.لكن، إذا نظرت إلى الوثائق، هناك عدد من المتطلبات التي يجب أن تضمنها لنفسك أمام النظام، والتي تنتهي جميعها في نفس الفكرة:على الرغم من أنك أجريت العملية عبر الإدخال/الإخراج، إلا أن الإجابة يجب أن تكون نتيجة دالة، كما هو متوقع من أي دالة هاسكل أخرى لا تعمل في IO:يجب أن يكون لها دائمًا نفس النتيجة دون آثار جانبية، بناءً على قيم الإدخال فقط.

هنا، نظرا للكود الخاص بك، قطعا هذه ليست القضيه, ، لأنك تقرأ من ملف.يجب عليك فقط مواصلة العمل داخل IO monad، عن طريق الاتصال بـ IO monad readJFile من داخل وظيفة أخرى مع نوع النتيجة IO something.وبعد ذلك، ستتمكن من قراءة القيمة داخل ملف IO غلاف (يتواجد في IO نفسك)، اعمل عليها، ثم أعد لف النتيجة في أخرى IO عند العودة.

No, there is no safe way to get a value out of the IO monad. Instead you should do the work inside the IO monad by applying functions with fmap or bind (>>=). Also you should use decode instead of eitherDecode when you want your result to be in Maybe.

getJson :: IO B.ByteString
getJson = B.readFile jsonFile

parseResponse :: B.ByteString -> Maybe Response
parseResponse = decode

readJFile :: IO (Maybe Response)
readJFile = fmap parseResponse getJSON

You could also use do notation if that is clearer to you:

readJFile :: IO (Maybe Response)
readJFile = do
    bytestring <- getJson
    return $ decode bytestring

Note that you dont even need the parseResponse function since readJFile specifies the type.

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