Jest dołączany jako członek, aby umożliwić użytkownikom dostosowanie go do szybkości i wydaje mi się, że jest zgodny z >>
.
Myślę, że może być szybciej w przypadku monada czytelnika ((->) r)
.
x <$ _ = const x
vs
x <$ fa = fmap (const x) fa = (const x) . fa
chociaż, to jest naprawdę kwestia optymalizacji kompilatora. I wydaje się, że nie jest on zdefiniowany dla monady czytelnika w bazie.
Może to również prowadzić do zwiększenia wydajności w przypadku ścisłych kolekcji. Mianowicie:
data Strict a = Strict !a
instance Functor Strict where
fmap f (Strict a) = Strict (f a)
x <$ _ = Strict x
nie jest to zgodne z przepisami obowiązującymi w zakresie funktur, ale mimo to możesz chcieć to zrobić w niektórych sytuacjach.
Trzeci przykład pochodzi z nieskończonych zbiorów.Rozważmy nieskończoną list
data Long a = Cons a (Long a)
instance Functor Long where
fmap f (Cons x xs) = Cons (f x) (fmap f xs)
który działa dobrze, ale myślę o
countUpFrom x = Cons x (countUpFrom (x+1))
ones = 1 <$ (countUpFrom 0)
teraz, z naszej definicji, która będzie rozwijać się
ones = 1 <$ (countUpFrom 0)
= fmap (const 1) (countUpFrom 0)
= Cons (const 1 0) (fmap (const 1) (countUpFrom 1)
= Cons (const 1 0) (Cons (const 1 1) (fmap (const 1) (countUpFrom 2))
że jest, to będzie przeznaczyć całą masę Cons
komórki podczas przechodzenia przez tę listę. Chociaż, z drugiej strony, jeśli zdefiniowano
x <$ _ = let xs = Cons x xs in xs
niż
ones = 1 <$ countUpFrom 0
= let xs = Cons 1 xs in xs
które weszło w związki małżeńskie. Jeszcze bardziej skrajny przykład pochodzi z nieskończonych drzewach
data ITree a = ITree a (ITree a) (ITree a)
Zasadniczo możesz mieć bardziej efektywny przypadek użycia. Jeśli nie, pozostaw domyślne. Oznacza to, że dbasz tylko o strukturę, a nie wartość. – PyRulez