2016-04-27 6 views
4

Ich folge Real World OCaml, um mit der Sprache zu beginnen, und an einem Punkt, ich bin es, s-Ausdrücke in einer Modul-Signatur zu verwenden. Hier ist meine mli Datei:Kann s-Ausdrücke nicht verwenden

open Core.Std 

(** Configuration type for query handlers *) 
type config with sexp 

(** Name of the query handler *) 
val name : string 

(** Query handler abstract type *) 
type t 

(** Create a query handler from an existing [config] *) 
val create : config -> t 

(** Evaluate a query, where both input and output an s-expressions. *) 
val eval : t -> Sexp.t -> Sexp.t Or_error.t 

Aber, wenn eine Implementierung dieser Schnittstelle kompilieren, erhalte ich folgende Fehlermeldung:

File "Query_Handler.mli", line 4, characters 12-16: 
Error: Syntax error 
Command exited with code 2. 

So öffnete ich utopwith sexp auf ein einfacheres Beispiel, um zu versuchen:

module type Test = sig 
    type t with sexp 
end;; 

Aber ich bekomme den folgenden Fehler:

Error: Parse Error: "end" expected after [sig_items] (in [module type]) 

Allerdings ist sexplib installiert und weder das Buch noch meine Suche im Internet erwähnen irgendwelche "Voraussetzungen" für die Verwendung dieser Syntax.

Ich fühle mich wie ich etwas vermisse. Irgendeine Idee? :(

+0

. Das mit Sexp-Syntax beruht auf einer Camlp4-Erweiterung - das sollte in dem Buch irgendwo vor der Verwendung erklärt werden.Der moderne Weg, dies zu tun wäre, den ppx-Erweiterungsmechanismus stattdessen zu verwenden.Ich glaube, Jane Street haben alles, was notwendig ist freigegeben auch als ppx Version, dies ist nicht erklärbar d im Buch, da es eine neue Sprachfunktion ist. Ich weiß nicht, wo ich nachschlagen soll - Google ist dein Freund, denke ich. – user3240588

+0

Zeigen Sie, wie Sie es kompilieren, welchen Befehl verwenden Sie? –

+0

Wenn Sie mehr Informationen darüber möchten, ist dies Kapitel 10: * First-Class-Module *. Die mli heißt 'Query_Handler.mli' und die' ml', 'Query_Handler.ml'. Ich kompiliere es mit 'corebuild Query_Handler.native'. Außerdem benutze ich ArchLinux und das Paket 'camlp4' ist installiert. – RichouHunter

Antwort

3

Dies ist, weil die sexp Bibliothek war neu geschrieben worden Extension Point, instead of Camlp4.

open Core.Std 

module type Query_handler = sig 
    (** Configuration for a query handler. Note that this can be 
     Converted to and from an s-expression *) 
    type config [@@deriving sexp] 

    (** The name of the query-handling service *) 
    val name : string 

    (** The state of the query handler *) 
    type t 

    (** Create a new query handler from a config *) 
    val create : config -> t 

    (** Evaluate a given query, where both input and output are 
     s-expressions *) 
    val eval : t -> Sexp.t -> Sexp.t Or_error.t 
end 

module Unique = struct 
    type config = int [@@deriving sexp] 
    type t = { mutable next_id: int } 

    let name = "unique" 
    let create start_at = { next_id = start_at } 

    let eval t sexp = 
    match Or_error.try_with (fun() -> unit_of_sexp sexp) with 
    | Error _ as err -> err 
    | Ok() -> 
     let response = Ok (Int.sexp_of_t t.next_id) in 
     t.next_id <- t.next_id + 1; 
     response 
end 

module List_dir = struct 
    type config = string [@@deriving sexp] 
    type t = { cwd: string } 

    (** [is_abs p] Returns true if [p] is an absolute path *) 
    let is_abs p = 
    String.length p > 0 && p.[0] = '/' 

    let name = "ls" 
    let create cwd = { cwd } 

    let eval t sexp = 
    match Or_error.try_with (fun() -> string_of_sexp sexp) with 
    | Error _ as err -> err 
    | Ok dir -> 
     let dir = 
     if is_abs dir then dir 
     else Filename.concat t.cwd dir 
     in 
     Ok (Array.sexp_of_t String.sexp_of_t (Sys.readdir dir)) 
end 

module type Query_handler_instance = sig 
    module Query_handler : Query_handler 
    val this : Query_handler.t 
end 

let build_instance (type a) 
        (module Q : Query_handler with type config = a) 
        config = 
    (module struct 
    module Query_handler = Q 
    let this = Q.create config 
    end : Query_handler_instance) 

let build_dispatch_table handlers = 
    let table = String.Table.create() in 
    List.iter handlers 
      ~f:(fun ((module I : Query_handler_instance) as instance) -> 
       Hashtbl.replace table ~key:I.Query_handler.name ~data:instance); 
    table 

let dispatch dispatch_table name_and_query = 
    match name_and_query with 
    | Sexp.List [Sexp.Atom name; query] -> 
    begin match Hashtbl.find dispatch_table name with 
    | None -> 
     Or_error.error "Could not find matching handler" 
         name String.sexp_of_t 
    | Some (module I : Query_handler_instance) -> 
     I.Query_handler.eval I.this query 
    end 
    | _ -> 
    Or_error.error_string "malformed query" 

let rec cli dispatch_table = 
    printf ">>> %!"; 
    let result = 
    match In_channel.input_line stdin with 
    | None  -> `Stop 
    | Some line -> 
     match Or_error.try_with (fun() -> Sexp.of_string line) with 
     | Error e -> `Continue (Error.to_string_hum e) 
     | Ok query -> 
      begin match dispatch dispatch_table query with 
      | Error e -> `Continue (Error.to_string_hum e) 
      | Ok s -> `Continue (Sexp.to_string_hum s) 
      end; 
    in 
    match result with 
    | `Stop   ->() 
    | `Continue msg -> 
    printf "%s\n%!" msg; 
    cli dispatch_table 

let unique_instance = build_instance (module Unique) 0 
let list_dir_instance = build_instance (module List_dir) "/var"          

module Loader = struct 
    type config = (module Query_handler) list sexp_opaque [@@deriving sexp] 

    type t = { known : (module Query_handler)   String.Table.t 
      ; active : (module Query_handler_instance) String.Table.t 
      } 

    let name ="loader" 

    let create known_list = 
    let active = String.Table.create() in 
    let known = String.Table.create() in 
    List.iter known_list 
       ~f:(fun ((module Q : Query_handler) as q) -> 
       Hashtbl.replace known ~key:Q.name ~data:q); 
    { known; active } 

    let load t handler_name config = 
    if Hashtbl.mem t.active handler_name then 
     Or_error.error "Can't re-register an active handler" 
        handler_name String.sexp_of_t 
    else 
     match Hashtbl.find t.known handler_name with 
     | None -> 
     Or_error.error "Unknown handler" handler_name String.sexp_of_t 
     | Some (module Q : Query_handler) -> 
     let instance = 
      (module struct 
       module Query_handler = Q 
       let this = Q.create (Q.config_of_sexp config) 
      end : Query_handler_instance) 
     in 
     Hashtbl.replace t.active ~key:handler_name ~data:instance; 
     Ok Sexp.unit 

    let unload t handler_name = 
    if not (Hashtbl.mem t.active handler_name) then 
     Or_error.error "Handler not active" handler_name String.sexp_of_t 
    else if handler_name = name then 
     Or_error.error_string "It's unwise to unload yourself" 
    else (
     Hashtbl.remove t.active handler_name; 
     Ok Sexp.unit 
    ) 

    type request = 
    | Load of string * Sexp.t 
    | Unload of string 
    | Known_services 
    | Active_services [@@deriving sexp] 

    let eval t sexp = 
    match Or_error.try_with (fun() -> request_of_sexp sexp) with 
    | Error _ as err -> err 
    | Ok resp -> 
     match resp with 
     | Load (name,config) -> load t name config 
     | Unload name  -> unload t name 
     | Known_services  -> 
      Ok [%sexp ((Hashtbl.keys t.known) : string list)] 
     | Active_services -> 
      Ok [%sexp ((Hashtbl.keys t.active) : string list)] 
end 
+0

Ja, das hat den Trick gemacht, vielen Dank! Es funktioniert aber immer noch nicht in "Utop". :(Muss ich eine bestimmte Bibliothek dafür laden? – RichouHunter

+0

Side question: Soll ich mit dem Autor in Verbindung treten, um das herauszufinden? – RichouHunter

+0

Ich denke, es ist hilfreich. – user962278

1

verwenden Dies ist mein ~/.ocamlinit;. Nur die camlp4 Kommentar aus utop sollte glücklich arbeiten

#use "topfind";; 
#warnings "+9" 
#thread;; 
(*camlp4;;*) 
#require "core.top";; 
#require "core_extended";; 
#require "core_bench";; 
#require "ppx_jane";; 
#require "ctypes";; 
#require "ctypes.foreign";; 
+0

Ja, habe den Trick auch, danke nochmal. Also nehme ich camlp4 wird überhaupt nicht mehr verwendet? – RichouHunter

+0

Wie ich finde. Normale Syntaxerweiterungen sollten "Extension Point" verwenden. Camlp4 wurde jetzt in Camlp5 umbenannt. Es sollte verwendet werden, um Sprachen zu entwickeln, die nicht sehr wie OCaml sind. http : //pauillac.inria.fr/~ddr/camlp5/doc/html/ – user962278

Verwandte Themen