2008-11-06 12 views
18

W Pythonie map() działa na wszystkich danych zgodnych z protokołem sekwencji. Czyni to Właściwą Rzecz^TM, czy podaję jej ciąg, listę, czy nawet krotkę.Czy OCaml ma ogólne funkcje map()/reduce()?

Nie mogę też dostać mojego ciasta w OCaml? Czy naprawdę nie mam innego wyjścia, jak tylko przyjrzeć się typowi kolekcji używam i znaleźć odpowiedni List.map lub Array.map lub Buffer.map lub String.map? Niektóre z nich nawet nie istnieją! Czy to jest to, o co proszę, niezwykłe? Muszę czegoś przegapić.

+0

Co zatem jest nie tak z koniecznością sprawdzenia dokumentacji i korzystania z odpowiedniej funkcji? –

Odpowiedz

17

Najbliżej do tego dojdzie moduł Enum w OCaml Batteries Included (dawniej z Extlib). Enum definiuje mapy i składa się na Enum.t; po prostu musisz użyć konwersji do/z Enum.t dla twojego typu danych. Konwersje mogą być dość lekkie, ponieważ Enum.t jest leniwy.

To, czego naprawdę chcesz, to styl w stylu Haskella: type classes, taki jak Foldable i Functor (który generalizuje "mapy"). Biblioteki Haskella definiują instancje Foldable i Functor dla list, tablic i drzew. Inną odpowiednią techniką jest "Scrap Your Boilerplate" approach do programowania ogólnego. Ponieważ OCaml nie obsługuje klas typów ani higher-kinded polymorphism, nie sądzę, abyś mógł wyrazić takie wzorce w swoim systemie typów.

+0

W języku ML system modułów wyższego rzędu rozwiązuje ten problem. –

+0

Nie zgadzam się, że zawijanie wszystkiego w funktora jest "rozwiązaniem" tego problemu. –

+0

Nie zgadzasz się z faktem.Spójrz na książkę Okasakiego z mnóstwem przykładów i porównanie, które wyjaśnia, dlaczego rozwiązanie OCaml jest lepsze od klas klas w tym kontekście. –

1

Problem polega na tym, że każdy kontener ma inną reprezentację i wymaga innego kodu do mapowania/zmniejszenia do iteracji. Dlatego istnieją oddzielne funkcje. Większość języków zapewnia pewien rodzaj ogólnego interfejsu dla kontenerów (takiego jak wspomniany protokół sekwencji), więc funkcje takie jak map/reduce mogą być realizowane w sposób abstrakcyjny, ale nie jest to robione dla typów, o których wspomniałeś.

-3

Dopóki zdefiniujesz typ t i val compare (: t-> t-> int) w twoim module, Map.Make da ci mapę, którą chcesz.

10

Istnieją dwa główne rozwiązania w SML:

  1. Jacques Garrigue już wdrożył składniowo-światło, ale nieefektywne podejście do wielu struktur danych kilka lat temu. Po prostu owij kolekcje w obiekty zapewniające metodę map. Następnie możesz zrobić collection#map, aby użyć funkcji mapy dla każdego rodzaju kolekcji. Jest to bardziej ogólne niż twoje wymagania, ponieważ umożliwia zastępowanie różnych rodzajów struktur danych w czasie wykonywania. Jednak w praktyce nie jest to zbyt użyteczne, więc podejście to nigdy nie zostało szeroko przyjęte.

  2. Syntaktycznie cięższe, ale wydajne, niezawodne i statyczne rozwiązanie polega na użyciu funktorów do sparametryzowania kodu przez strukturę danych, której używasz. To sprawia, że ​​używanie kodu z różnymi strukturami danych jest banalne. Zobacz tłumaczenie OCaml autorstwa Markusa Mottla z książki Okasaki "Czysto funkcjonalne struktury danych" na kilka świetnych przykładów.

Jeśli nie szukasz tego rodzaju władzy i po prostu chcą zwięzłość wtedy, oczywiście, można po prostu utworzyć alias moduł z krótszą nazwą (np moduł S = String).