خدعة من أجل "إعادة استخدام" الحجج في هاسكل؟
-
30-09-2019 - |
سؤال
من وقت لآخر ، أتعثر حول المشكلة التي أريد التعبير عنها "الرجاء استخدام الوسيطة الأخيرة مرتين" ، على سبيل المثال لكتابة نمط pointfree أو تجنب lambda. على سبيل المثال
sqr x = x * x
يمكن أن تكتب كما
sqr = doubleArgs (*) where
doubleArgs f x = f x x
أو النظر في هذه الوظيفة أكثر تعقيدًا قليلاً (مأخوذة من هذا السؤال):
ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs)
يمكنني كتابة هذا الكود pointfree إذا كانت هناك وظيفة مثل هذه:
ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where
dup f f1 f2 x = f (f1 x) (f2 x)
لكن بما أنني لا أجد شيئًا مثل Doubleargs أو DUP في Hoogle ، لذلك أعتقد أنني قد أفتقد خدعة أو تعبيرًا هنا.
المحلول
من Control.Monad
:
join :: (Monad m) -> m (m a) -> m a
join m = m >>= id
instance Monad ((->) r) where
return = const
m >>= f = \x -> f (m x) x
التوسع:
join :: (a -> a -> b) -> (a -> b)
join f = f >>= id
= \x -> id (f x) x
= \x -> f x x
إذن أجل، Control.Monad.join
.
أوه ، ولثالتك على سبيل المثال ، هل حاولت استخدام الترميز التطبيقي (من Control.Applicative
):
ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails
(أنا أيضا لا أعرف لماذا الناس مولعين جدا a ++ (x:b)
بدلاً من a ++ [x] ++ b
... إنها ليست أسرع - سوف يعتني به Inliner - والأخير أكثر تماثلًا! اوه حسناً)
نصائح أخرى
غالبًا ما يسمى ما تسميه "Doubleargs" DUP - إنه Combinator W (الذي يسمى Warbler في السخرية من الطائر المحاكي) - "The Elementary Duplicator".
ما تسميه "DUP" هو في الواقع combinator "starling-prime".
لدى Haskell "أساس combinator" صغير إلى حد ما ، راجع البيانات مثيل وظيفي ، Lifta2 & LiftM2 هما Starling-Prime). لا يبدو أن هناك الكثير من الحماس في المجتمع لتوسيع البيانات. وظيفية ، لذلك في حين أن المجموعتين ممتعة بشكل جيد ، فقد أصبحت براغمات تفضيلها في المواقف التي لا يتوفر فيها المشابك بشكل مباشر.
إليك حل آخر للجزء الثاني من سؤالي: الأسهم!
import Control.Arrow
ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++))
ال &&&
("Fanout") يوزع وسيطة على وظيفتين وإرجاع زوج النتائج. >>>
("ثم") يعكس ترتيب تطبيق الوظيفة ، والذي يتيح أن يكون لديك سلسلة من العمليات من اليسار إلى اليمين. second
يعمل فقط في الجزء الثاني من الزوج. بالطبع تحتاج إلى uncurry
في النهاية لتغذية الزوج في وظيفة تتوقع وسيطتين.