سؤال

لدي بنية شجرة بسيطة:

data Tree a = Leaf | Node a (Tree a) (Tree a)

و قابلة للطي تطبيق:

import qualified Data.Foldable as F

instance F.Foldable Tree where
  foldMap f Leaf         = mempty
  foldMap f (Node x l r) = F.foldMap f l `mappend`
                           f x           `mappend`
                           F.foldMap f r

وهو يعمل على الرغم من عدم وجود تطبيق ل Monoid ولا يمكنني استخدام أي منهما mappend ولا mempty في الكود الخاص بي. ثم كيف يفعل هذا Foldable عمل التنفيذ؟

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

المحلول

إذا قمت بفحص النوع foldMap

class Foldable f where
  foldMap :: Monoid m => (a -> m) -> f a -> m

سترى أنه يحتوي على نوع غير محدود m. بشكل عام عندما يحدث هذا يعني ذلك m ممكن ان يكون اى شئ, ، ولكن هنا يقيد أيضا m مع Monoid m. هذا هو Monoid يأتي من.

تجدر الإشارة إلى أنه إذا لم يكن لدينا Monoid على سبيل المثال ، من الصعب للغاية تحديد وظيفة تُرجع قيمة "يمكن أن تكون أي شيء". إذا حاولت ذلك ، فستجد أنه من المستحيل تقريبًا (بدون "الغش").

impossible :: Int -> b -- no constraints on `b` at all!
impossible i = ...?

لكن من السهل جدًا أن نعرف قليلاً عن النوع

veryPossible  :: Num b => Int -> b
veryPossible  i = fromIntegral i
-- or
veryPossible2 i = fromIntegral (i * i) + fromIntegral i

كمثال آخر ، فكر في نوع التعبير

expr m = mconcat [m <> m <> mempty, mempty <> m]

نظرًا لأن هذا التعبير مبني على أساس بعض القيمة غير المعروفة m ويستخدم فقط الوظائف في Monoid الطبقة أو مشتقاتها ، يعكس ذلك. النوع الأكثر عمومية من expr هو

expr :: Monoid m => m -> m

مرة أخرى هنا ، m هو متغير نوع مجاني مقيد ليكون بعض Monoid.


السبب foldMap يتيح لك استخدام Monoid الوظائف هي لأنه يقيد بشكل صريح أنواع الأشياء m في نوع التوقيع يمكن أن يكون. من خلال وضع القيود هناك ، نكتسب المزيد من القوة للتلاعب بها.

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