Cześć
Dręczy mnie taki problem:
W Haskellu Listy mają swoje własne dedykowane api jak operator ++ i funkcja map. Istnieją też dla listy implementacje typeclass Semigroup i Functor. Semigroup dostarcza operator <> który robi dokładnie to samo co operator ++, a Functor dostarcza funkcję fmap, która robi dokładnie to samo co funkcja map.
Są może jakieś zalecenia i dobre praktyki dla Haskella którego api należy używać? Czy tego dedykowanego dla list czy tego ogólnego które można zaimplementować dla wszystkich typów danych?
api List vs Półgrupa i Funktor
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Silesia/Marki
- Postów: 5550
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: XML Hills
Są może jakieś zalecenia i dobre praktyki dla Haskella którego api należy używać?
Popatrzyłbym na jakieś popularne aplikacje i biblioteki Haskellowe (pomijając bibliotekę standardową).
Czy tego dedykowanego dla list czy tego ogólnego które można zaimplementować dla wszystkich typów danych?
Ja bym to rozgraniczył ten sposób:
- Jeśli używam kolekcji i tylko kolekcja ma sens w danym miejscu, a nie dowolny funktor czy monada to używam API idiomatycznego dla kolekcji.
- Jeśli używam jakiegoś typu, który może być kolekcją, ale kod ma sens i potencjalnie jest przydatny dla wielu typów nie będących kolekcjami to używam API z typeclass. Jednocześnie warto zmienić kod tak by przyjmował ten funktor czy monadę, a nie konkretnie kolekcję i wtedy wiadomo po co nastąpiła zmiana użytych operatorów.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 426
Wszystko zależy od tego jak generyczny ma być twój kod. Jeżeli twoja funkcja ma obsługiwać tylko stringa, to najprościej dać ++. mappend albo <> pozwoli Ci na pisanie bardziej generycznych funkcji.
Pamiętaj, że Funktor to bardzo ogólna abstrakcja i jeżeli napiszesz funkcję, która na niej operuję, to będziesz mógł do niej przekazywać nawet inne funkcje.
foo = fmap (+ 2)
bar = foo (+ 4)
main = print $ bar 5
Jeżeli twoja funkcja ma być aż tak generyczna, to nie widzę problemu, żeby używać ogólnych abstrakcji. Problem w tym, że taka lista jest instancją wielu klas i to
foo :: [Integer] -> Integer
foo = foldr (-) 0 . fmap (+ 2)
jest jednak czytelniejsze od tego
bar :: (Foldable m, Functor m, Num a) => m a -> a
bar = foldr (-) 0 . fmap (+ 2)