2012-10-11 54 views
6

La extensión de sintaxis de Sexplib facilita la serialización y la deserialización de estructuras de datos arbitrarias definidas por el usuario en OCaml. Por lo general, se realiza mediante la adición de una anotación de with sexp al final de una definición de tipo:¿Cómo se puede usar sexplib con tipos de funtores como Map?

type a = A of int | B of float with sexp 

Esto no parece generalizar directamente a los tipos basados ​​en los funtores, ni tampoco está claro cómo el tipo estándar de los convertidores Sexplib pueden capturar incluso los funtores estándar.

Hasta ahora he solucionado esto al acoplar una instancia de tipo de mapa específica (por ejemplo int Map.Make(String).t) a una lista antes de la serialización, y viceversa, pero seguramente esto no ha sido pasado por alto por los autores generalmente ambiciosos de Sexplib/Jane Street Core. También noté que versiones anteriores de de Batteries se mezclan en serialización de sexp personalizado con sus módulos principales como [Bat] Map, pero que esto ha sido eliminado por algún tiempo.

¿Cómo se usan comúnmente los mapas u otros tipos de funcionamientos complejos con la serialización de Sexplib?

+2

Creo que usaría una biblioteca estándar extendida con funciones de conversión sexplib generalizadas para eso. ¿Has mirado 'Core'? Solo pasé 5 minutos con él, pero en estos 5 minutos apliqué el functor 'Set.Make' y me pidió las funciones de conversión sexplib en el tipo de argumento para que pudiera construir funciones de conversión sexplib para el tipo de conjunto resultante. –

Respuesta

1

Una forma es definir un nuevo functor que tome la información adicional necesaria para serializar los datos. Aquí hay una implementación completa que he usado en el pasado con las baterías. Tenga en cuenta que también prefiero la versión sin formato y etiquetada de Map, así que los abrí, pero por supuesto podría eliminarla.

module type SEXPABLE = sig 
    type t 
    val sexp_of_t : t -> Sexplib.Sexp.t 
    val t_of_sexp : Sexplib.Sexp.t -> t 
end 

module Map = struct 

    module type S = sig 
    include BatMap.S 
    include module type of Labels 
    include module type of Exceptionless 
    val sexp_of_t : ('a -> Sexplib.Sexp.t) -> 'a t -> Sexplib.Sexp.t 
    val t_of_sexp : (Sexplib.Sexp.t -> 'a) -> Sexplib.Sexp.t -> 'a t 
    end 

    module Make (Ord : BatInterfaces.OrderedType) 
       (Sexpable : SEXPABLE with type t = Ord.t) 
       : S with type key = Ord.t = struct 
    include BatMap.Make(Ord) 
    include Labels 
    include Exceptionless 

    open Sexplib.Sexp 
    open Sexplib.Conv 

    let sexp_of_t sexp_of_data t = 
     let f ~key ~data ans = List [Sexpable.sexp_of_t key; sexp_of_data data] :: ans in 
     List (fold ~f ~init:[] t) 

    let t_of_sexp data_of_sexp sexp = match sexp with 
     | Atom _ -> of_sexp_error "Map.Make(...).t_of_sexp: list needed" sexp 
     | List l -> 
      let f ans = function 
      | List [key_sexp; data_sexp] -> 
       let key = Sexpable.t_of_sexp key_sexp in 
       let data = data_of_sexp data_sexp in 
       add ~key ~data ans 
      | List _ | Atom _ -> 
       of_sexp_error "Map.Make(...).t_of_sexp: 2-tuple list needed" sexp 
      in 
      List.fold_left ~f ~init:empty l 
    end 
end 

Si recuerdo bien, las baterías eliminaron tales características para reducir las dependencias en bibliotecas adicionales. Su otra opción es usar Core, que tiene estas funciones listas para usar.

Cuestiones relacionadas