package swipl
Bindings to SWI-Prolog for OCaml
Install
Dune Dependency
Authors
Maintainers
Sources
swipl-ocaml-v0.5.tar.gz
md5=a4ea377afe5c52496bf445621ad2e02b
sha512=bcb55c99ae6a2308028d813c78e512901e4ab4f1bb6f054a95de044abee9e420ff9100e4bb6e00520977b800039e8e5338739a4b2ace28cbf8961ba415e33230
doc/src/swipl.swipl/swipl.ml.html
Source file swipl.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
(* SWIPL-OCaml Copyright (C) 2021 Kiran Gopinathan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. *) module Raw = Raw let module_sep = lazy (Raw.Functor.functor_ (Raw.Atom.atom ":") 2) let conjunction = lazy (Raw.Functor.functor_ (Raw.Atom.atom ",") 2) let disjunction = lazy (Raw.Functor.functor_ (Raw.Atom.atom ";") 2) let apply = lazy (Raw.Functor.functor_ (Raw.Atom.atom "apply") 2) let call1 = lazy (Raw.Functor.functor_ (Raw.Atom.atom "call") 1) type ty = [ `Atom | `Blob | `Bool | `Dict | `Float | `Integer | `ListPair | `Nil | `Rational | `String | `Term | `Variable ] type ctx = Raw.ForeignFrame.t option type query = Raw.Query.qid type module_ = Raw.Module.t [@@deriving eq, ord] let module_ str = Raw.Module.new_module (Raw.Atom.atom str) type fn = Raw.Functor.t [@@deriving eq, ord] type atom = Raw.Atom.t [@@deriving eq, ord] type t = | Term of Raw.Term.t | Atom of Raw.Atom.t | App of Raw.Module.t option * Raw.Functor.t * t list | Conjunction of t * t | Disjunction of t * t [@@deriving eq, ord] let create_term (_ctx: ctx) = Raw.Term.new_ref () let create_terms (_ctx: ctx) n = Raw.Term.new_refs n let of_term term = Term term let encode_string ctx str = let t = create_term ctx in assert(Raw.Term.put_string_chars t str); t let encode_list ctx ls = let rec loop result = function | [] -> assert (Raw.Term.put_nil result); result | h :: t -> let result = loop result t in assert (Raw.Term.cons_list result h result); result in loop (create_term ctx) ls let array_of_list ctx args = let length = List.length args in if length = 0 then Raw.Term.Array.empty else begin let terms = create_terms ctx length in List.iteri (fun ind term -> assert (Raw.Term.put_term (Raw.Term.Array.get terms ind) term)) args; terms end let atom ctx v = let result = create_term ctx in Raw.Term.put_atom result v; result let app2 ctx fn arg1 arg2 = let result = create_term ctx in assert (Raw.Term.cons_functor2 result fn arg1 arg2); result let app ctx fn args = let result = create_term ctx in let args = array_of_list ctx args in assert (Raw.Term.cons_functor result fn args); result let rec to_term ctx = function | Term t -> t | App (None, fn, args) -> app ctx fn (List.map (to_term ctx) args) | App (Some module_, fn, args) -> let fn = let lazy sep = module_sep in let module_ = Raw.Module.module_name module_ in let fn = Raw.Functor.name fn in app2 ctx sep (atom ctx module_) (atom ctx fn) in let args = List.map (to_term ctx) args in let args = encode_list ctx args in let lazy apply = apply in app2 ctx apply fn args | Conjunction (l,r) -> let lazy conjunction = conjunction in let l = to_term ctx l in let r = to_term ctx r in app2 ctx conjunction l r | Disjunction (l,r) -> let lazy disjunction = disjunction in let l = to_term ctx l in let r = to_term ctx r in app2 ctx disjunction l r | Atom a -> atom ctx a let eval ctx = let flags = Raw.Q.(normal + ext_status + pass_exception) in function | Term t -> let lazy call = call1 in let pred = Raw.Predicate.pred call in Raw.Query.open_query ~flags pred (array_of_list ctx [t]) | App (module_, fn, args) -> let pred = Raw.Predicate.pred ?module_ fn in let args = array_of_list ctx (List.map (to_term ctx) args) in Raw.Query.open_query ?module_ ~flags pred args | Atom a -> let fn = Raw.Functor.functor_ a 0 in let pred = Raw.Predicate.pred fn in Raw.Query.open_query ~flags pred Raw.Term.Array.empty | Conjunction (l,r) -> let lazy conjunction = conjunction in let conjunction = Raw.Predicate.pred conjunction in Raw.Query.open_query ~flags conjunction (array_of_list ctx [to_term ctx l; to_term ctx r]) | Disjunction (l,r) -> let lazy disjunction = disjunction in let disjunction = Raw.Predicate.pred disjunction in Raw.Query.open_query ~flags disjunction (array_of_list ctx [to_term ctx l; to_term ctx r]) let initialise () = Raw.initialise () let with_ctx f = let frame = Raw.ForeignFrame.open_frame () in let res = f (Some frame) in Raw.ForeignFrame.close_frame frame; res let show t = with_ctx (fun ctx -> to_term ctx t |> Raw.Term.get_chars) |> Option.value ~default:"None" let pp fmt t = Format.pp_print_string fmt (show t) let fresh ctx = of_term (create_term ctx) module Syntax = struct let (/@) fn x = Raw.Functor.functor_ (Raw.Atom.atom fn) x let (!) x = Atom (Raw.Atom.atom x) let app ?module_ fn args = App (module_, fn, args) let (&&) l r = Conjunction (l,r) let (||) l r = Disjunction (l,r) end let fold_solutions fn query = let any_seen = ref false in let rec loop () = match Raw.Query.next_solution query with | Raw.Query.Result.Bool true -> any_seen := true; begin match fn `Solution with | Some `Close -> assert (Raw.Query.close_query query) | Some `Cut -> assert (Raw.Query.cut_query query) | None -> loop () end | Raw.Query.Result.Bool false -> assert (Raw.Query.close_query query) | Raw.Query.Result.Last -> any_seen := true; begin match fn `Last with | Some `Close -> assert (Raw.Query.close_query query) | Some `Cut -> assert (Raw.Query.cut_query query) | None -> assert (Raw.Query.close_query query) end | Raw.Query.Result.Exception -> match Raw.Exception.exn query with | None -> assert (Raw.Query.close_query query) | Some exn -> ignore @@ begin try fn (`Exception (Term exn)) with e -> (Raw.Exception.clear_exn (); raise e) end; Raw.Exception.clear_exn (); assert (Raw.Query.close_query query) in begin try loop () with | e -> assert (Raw.Query.close_query query); raise e end; !any_seen let iter_solutions ?(on_error=fun _ -> ()) query fn = fold_solutions (function | `Exception e -> on_error e; None | _ -> fn (); None ) query let first_solution query = fold_solutions (function | `Exception e -> failwith ("Prolog query raised exception: " ^ show e) | `Last -> Some `Cut | `Solution -> Some `Cut ) query let last_solution query = fold_solutions (function | `Exception e -> failwith ("Prolog query raised exception" ^ show e) | `Last -> Some `Cut | `Solution -> None ) query let call ctx t = let query = eval ctx t in ignore @@ first_solution query let extract_list ctx term = let term = to_term ctx term in let rec loop term = if Raw.Term.get_nil term then [] else let hd = create_term ctx in let tl = create_term ctx in assert (Raw.Term.get_list term hd tl); (of_term hd) :: (loop tl) in loop term let atom t = Raw.Atom.atom t let extract_atom ctx term = Raw.Term.get_atom (to_term ctx term) |> Option.get let show_atom atom = Raw.Atom.chars atom let pp_atom fmt atom = Format.pp_print_string fmt (show_atom atom) let extract_bool ctx term = Raw.Term.get_bool (to_term ctx term) |> Option.get let extract_int ctx term = Raw.Term.get_integer (to_term ctx term) |> Option.get let extract_float ctx term = Raw.Term.get_float (to_term ctx term) |> Option.get let extract_string ctx term = Raw.Term.get_string_chars (to_term ctx term) |> Option.get let extract_functor ctx term = let (name, arity) = Raw.Term.get_name_arity (to_term ctx term) |> Option.get in let rec loop acc ind = if ind < arity then let arg = create_term ctx in assert (Raw.Term.get_arg (ind + 1) (to_term ctx term) arg); loop ((of_term arg) :: acc) (ind + 1) else List.rev acc in (name, loop [] 0) let typeof = function | Term t -> Raw.Term.term_type t | Atom _ -> `Atom | App (_, _, _) | Conjunction (_, _) | Disjunction (_, _) -> `Term let encode_list ctx args = of_term (List.map (to_term ctx) args |> encode_list ctx) let encode_string ctx str = of_term (encode_string ctx str) let load_source txt = let user = lazy Syntax.(! "user") in let open_string = lazy Syntax.("open_string" /@ 2) in let load_files = lazy Syntax.("load_files" /@ 2) in let stream = lazy Syntax.("stream" /@ 1) in let open_string txt out = Syntax.(app (Lazy.force open_string) [txt; out]) in let load_files int opts = Syntax.(app (Lazy.force load_files) [int; opts]) in let stream out = Syntax.(app (Lazy.force stream) [out]) in let open_source ctx src = let out = fresh ctx in Syntax.(open_string (encode_string ctx src) out && load_files (Lazy.force user) (encode_list ctx [stream out])) in with_ctx (fun ctx -> call ctx (open_source ctx txt) )
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>