2008-11-06 28 views
18

En Python map() funciona en cualquier dato que siga el protocolo de secuencia. Hace The Right Thing^TM si le doy una cadena o una lista o incluso una tupla.¿Tiene OCaml funciones de mapa general()/reduce()?

¿No puedo comer mi pastel en OCaml también? ¿Realmente no tengo más remedio que mirar el tipo de colección que estoy usando y encontrar un List.map correspondiente o un Array.map o un Buffer.map o un String.map? ¡Algunos de estos ni siquiera existen! Es lo que estoy pidiendo inusual? Debo estar perdiendo algo.

+0

Entonces, ¿qué hay de malo con tener que buscar la documentación y usar la función apropiada? –

Respuesta

17

Lo más cerca que obtendrá de esto es el módulo Enum en OCaml Batteries Included (anteriormente Extlib). Enum define mapas y pliegues sobre Enum.t; solo tiene que usar una conversión a/desde Enum.t para su tipo de datos. Las conversiones pueden ser bastante livianas, porque Enum.t es flojo.

Lo que realmente quieres es Haskell-style type classes, como Foldable y Functor (que generaliza los "mapas"). Las bibliotecas de Haskell definen instancias de Foldable y Functor para listas, matrices y árboles. Otra técnica relevante es el "Scrap Your Boilerplate" approach para la programación genérica. Como OCaml no es compatible con las clases de tipo higher-kinded polymorphism, no creo que pueda expresar patrones como estos en su sistema de tipos.

+0

En ML, el sistema de módulo de orden superior resuelve este problema. –

+0

No estoy de acuerdo en que envolver todo en un functor sea una "solución" a este problema. –

+0

Estás en desacuerdo con un hecho.Mire el libro de Okasaki para encontrar muchos ejemplos y una comparación que explique por qué la solución de OCaml es preferible al tipo de clases en este contexto. –

1

El problema es que cada contenedor tiene una representación diferente y requiere un código diferente para map/reduce para iterar sobre él. Esta es la razón por la cual hay funciones separadas. La mayoría de los lenguajes proporcionan algún tipo de interfaz general para contenedores (como el protocolo de secuencia que mencionas), por lo que funciones como map/reduce se pueden implementar de manera abstracta, pero esto no se hace para los tipos que mencionaste.

-3

Siempre y cuando defina un tipo t y val compare (: t-> t-> int) en su módulo, Map.Make le dará el mapa que desee.

10

Hay dos soluciones principales en OCaml:

  1. Jacques Garrigue ya se implementó un sintácticamente-luz, pero el enfoque ineficaz para muchas estructuras de datos hace varios años. Simplemente envuelve las colecciones en objetos que proporcionan un método map. Luego puede hacer collection#map para usar la función de mapa para cualquier tipo de colección. Esto es más general que sus requisitos porque permite sustituir diferentes tipos de estructuras de datos en tiempo de ejecución. Sin embargo, esto no es muy útil en la práctica, por lo que el enfoque nunca fue ampliamente adoptado.

  2. Una solución sintácticamente más pesada pero eficiente, robusta y estática es usar funtores para parametrizar su código sobre la estructura de datos que está utilizando. Esto hace que sea trivial reutilizar su código con diferentes estructuras de datos. Consulte las traducciones de OCaml de Markus Mottl del libro de Okasaki "Estructuras de datos puramente funcionales" para ver algunos ejemplos excelentes.

Si no busca ese tipo de poder y sólo quiere brevedad entonces, por supuesto, sólo puede crear un alias de módulo con un nombre más corto (por ejemplo, el módulo S = cadena de caracteres).