Niet-lege lijsten:
data NietLeeg a = Cons a (Maybe (NietLeeg a))vorm datatype geeft aanleiding tot functor:
class Functor f where
fmap :: (a -> b) -> (f a -> f b)instance Functor NietLeeg where
fmap f (Cons waarde rest) = Cons (f a) (fmap f <$> rest)class Foldable t where
-- een van deze twee is genoeg
foldMap :: Monoid m => (a -> m) -> t a -> m
foldr :: (a -> b -> b) -> b -> t a -> bfoldMap:- neem een monoïde
m - gooi alle waarden uit de structuur
tin die monoïde - voeg dan alles lineair samen
- neem een monoïde
foldr: zoals gewoonlijk
geen echte 'wetten' zoals er bij Functor en Applicative zijn
Ik vind foldMap het makkelijkste.
Centrale vraag:
- Hoe beschouw ik de elementen van mijn datastructuur één per één?
- Hoe pas ik de monoïdale operator
<>op die elementen toe?
instance Foldable NietLeeg where
foldMap :: (Monoid m) => (a -> m) -> NietLeeg a -> m
foldMap naarMonoïde (Cons waarde rest) = instance Foldable NietLeeg where
foldMap :: (Monoid m) => (a -> m) -> NietLeeg a -> m
foldMap naarMonoïde (Cons waarde Nothing) = naarMonoïde waarde
foldMap naarMonoïde (Cons waarde (Just rest)) = naarMonoïde waarde <> foldMap naarMonoïde restmaybe :: b -> (a -> b) -> Maybe a -> bDus opsplitsen in Nothing en Just rest is niet nodig:
maybe mempty (foldMap naarMonoïde) restis precies het goede element om mee te rechtsvermenigvuldigen.
instance Foldable NietLeeg where
foldMap :: (Monoid m) => (a -> m) -> NietLeeg a -> m
foldMap naarMonoïde (Cons waarde rest)
= naarMonoïde waarde <> maybe mempty (foldMap naarMonoïde) restStel dat Foldable t. Dan:
foldMap :: Monoid m => (a -> m) -> t a -> mfoldr :: (a -> b -> b) -> b -> t a -> b
zijn minimaal (de één levert de ander). Maar ook gratis zijn:
fold :: Monoid m => t m -> mfoldl :: (b -> a -> b) -> b -> t a -> btoList :: t a -> [a]null :: t a -> Boollength :: t a -> Intelem :: Eq a => a -> t a -> Boolmaximum :: Ord a => t a -> aminimum :: Ord a => t a -> asum :: Num a => t a -> aproduct :: Num a => t a -> a
class (Functor t, Foldable t) => Traversable where
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
sequenceA :: Applicative f => t (f a) -> f (t a)wtf?
-
traverse:- voor een bepaalde applicatieve functor
f, - neem een waarde van type
aen maak er eenbbinnenfvan - doe dat voor elke waarde van de structuur
- geef diezelfde structuur terug, in een
f
- voor een bepaalde applicatieve functor
-
sequenceA:- voor een bepaalde applicatieve functor
f, - neem een structuur vol
f a's - pas ze allemaal toe ("van links naar rechts")
- hul het resultaat in een
f
- voor een bepaalde applicatieve functor
traverse is een soort map met effecten.
(denk aan Maybe, Either, State, [], ...)
Traversable is voor Applicative wat Foldable is voor Monoid.
traverse f = sequenceA . fmap fsequenceA = traverse id
Basically gwn foldMap maar met traverse
Maar vaak gepruts met de waarde in de functor krijgen!
instance Traversable NietLeeg where
traverse :: (Applicative f) => (a -> f b) -> NietLeeg a -> f (NietLeeg b)
traverse naarApp (Cons waarde Nothing) = (`Cons` Nothing) <$> naarApp waarde
traverse naarApp (Cons waarde (Just rest)) = Cons <$> naarApp waarde <*> (Just <$> traverse naarApp rest)Maar Maybe is zelf ook een Traversable!
instance Traversable NietLeeg where
traverse :: (Applicative f) => (a -> f b) -> NietLeeg a -> f (NietLeeg b)
traverse naarApp (Cons waarde rest) = Cons <$> naarApp waarde <*> traverse (traverse naarApp) rest