ارتباك حول الكريات والأسلوب المجاني نقطة في Haskell
سؤال
كنت أحاول تنفيذ الوظيفة
every :: (a -> IO Bool) -> [a] -> IO Bool
الذي كان الموضوع ل هذا السؤال. وبعد حاولت القيام بذلك دون recursion صريحة. وبعد لقد توصلت إلى الكود التالي
every f xs = liftM (all id) $ sequence $ map f xs
لم تنجح وظيفتي لأنها لم تكن كسولا (والتي كانت مطلوبة في السؤال)، لذلك لا توجد upvotes هناك :-).
ومع ذلك، لم أتوقف هناك. حاولت أن أجعل الوظيفة خال من النقطة بحيث يكون أقصر (وربما أكثر برودة). منذ الحجج f
و xs
هي آخر منها في التعبير، لقد أسقطتها للتو:
every = liftM (all id) $ sequence $ map
لكن هذا لم ينجح كما هو متوقع، في الواقع لم ينجح على الإطلاق:
1 من 1] ترجمة الرئيسية (STK.HS، المفسر) STK.HS: 53: 42: تعذر مطابقة النوع المتوقع `[MA] ضد نوع الاستنتاج `(A1 -> B) -> [A1] -> [B] "في الحجة الثانية من` ($) "، وهي" خريطة "في الحجة الثانية من` ($)، وهي "تسلسل خريطة $" في التعبير: فشل LIFTM (كل المعرف) $ خريطة $ ، وحدات محملة: لا شيء.
لماذا هذا؟ كنت تحت الانطباع بأنه كان من الممكن ببساطة قطرة حجج وظيفة زائدة، والتي هي أساسا ما يدور حوله.
المحلول
تعريف $ هو
f $ x = f x
دعونا قوسا تماما وظيفتك:
every f xs = (liftM (all id)) (sequence ((map f) xs))
ونسخة الكتر الخاصة بك:
every = (liftM (all id)) (sequence map)
كما لاحظت، هذه ليست متطابقة. يمكنك فقط إسقاط الوسائط الوظيفية الزائدة عندما تكون آخر شيء مطبق. علي سبيل المثال،
f x = g c x
في الواقع
f x = (g c) x
وتطبيق (GC) إلى x يأتي آخر، حتى تتمكن من الكتابة
f = g c
نمط واحد مع مشغل التطبيق $ هو أنه غالبا ما يصبح مشغل التركيب. في إصدارات خالية من النقاط. هذا بسبب
f $ g $ x
أي ما يعادل
(f . g) $ x
علي سبيل المثال،
every f xs = liftM (all id) $ sequence $ map f xs
يمكن أن تصبح
every f xs = (liftM (all id) . sequence . map f) xs
عند أي نقطة يمكنك إسقاط XS:
every f = liftM (all id) . sequence . map f
القضاء على حجة F أكثر صعوبة، لأنه يتم تطبيقه قبل مشغل التركيب. دعونا نستخدم تعريف النقطة من http://www.haskell.org/haskellwiki/pointfree.:
dot = ((.) . (.))
مع النقاط، هذا هو
(f `dot` g) x = f . g x
وهذا هو بالضبط ما نحتاجه لجعل كل نقطة خالية من النقاط بالكامل:
every = (liftM (all id) . sequence) `dot` map
للأسف، بسبب القيود المفروضة في نظام Haskell، يحتاج هذا المرء إلى توقيع نوع صريح:
every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool