package OCanren-ppx
Implementation of miniKanren relational (logic) EDSL: PPX extensions
Install
Dune Dependency
Authors
Maintainers
Sources
OCanren-ppx-0.2.0.tbz
sha256=77dd4b9d2b41f908ee4871612e78f455f9f0200a8c70321fcc82ebb53c86b4f0
sha512=c5dab91f59060f5dd5aecef5665e9235d8317cf071603070b0eef84ba6dc3a6ac027a8cf8aa37262109edb309b83c05f355a53c6718e43438164740c6b8715d4
doc/src/ppx_distrib/ppx_distrib_expander.ml.html
Source file ppx_distrib_expander.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 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
(* * OCanren PPX * Copyright (C) 2016-2020 * Dmitrii Kosarev aka Kakadu, Petr Lozov * St.Petersburg State University, JetBrains Research *) open Base open Ppxlib open Ppxlib.Ast_builder.Default open Ppxlib.Ast_helper open Printf let (@@) = Caml.(@@) module Naming = struct let fabst_name = sprintf "g%s" let functor_name = sprintf "For_%s" end module TypeNameMap = Map.M(String) module FoldInfo = struct (* using fields of structure below we can generate ground type and the logic type *) type item = { param_name:string; rtyp: core_type; ltyp: core_type } exception ItemFound of item type t = item list let param_for_rtyp typ ts = let typ_repr = Pprintast.core_type Caml.Format.str_formatter typ; Caml.Format.flush_str_formatter () in try List.iter ts ~f:(fun i -> let new_repr = Caml.Format.asprintf "%a" Pprintast.core_type i.rtyp in if String.equal new_repr typ_repr then raise (ItemFound i) ); None with ItemFound i -> Some i let map ~f (xs: t) = List.map ~f xs let empty = [] let is_empty : t -> bool = List.is_empty let extend param_name rtyp ltyp ts = (* printf "extending by `%s`\n%!" param_name;*) {param_name; rtyp; ltyp} :: ts end (* TODO: maybe use Ppxlib.name_type_params_in_td ? *) let extract_names = List.map ~f:(fun typ -> match typ.ptyp_desc with | Ptyp_var s -> s | _ -> failwith (Caml.Format.asprintf "Don't know what to do with %a" Pprintast.core_type typ) ) let nolabel = Asttypes.Nolabel let get_param_names pcd_args = let Pcstr_tuple pcd_args = pcd_args in extract_names pcd_args let mangle_construct_name name = let low = String.mapi ~f:(function 0 -> Char.lowercase | _ -> Fn.id) name in match low with | "val" | "if" | "else" | "for" | "do" | "let" | "open" | "not" -> low ^ "_" | _ -> low let lower_lid lid = Location.{lid with txt = mangle_construct_name lid.Location.txt } module Located = struct include Located (* let mknoloc txt = { txt; loc = Location.none } *) let map_loc ~f l = {l with txt = f l.txt} end module Exp = struct include Exp let mytuple ~loc ?(attrs=[]) = function | [] -> failwith "bad_argument: mytuple" | [x] -> x | xs -> tuple ~loc ~attrs:attrs xs let apply ~loc f = function | [] -> f | xs -> apply ~loc f xs end let prepare_distribs ~loc fully_abstract_tname tdecl fmap_decl = let open Longident in let constructors = match tdecl.ptype_kind with | Ptype_variant c -> c | _ -> failwith "not implemented" in let gen_module_str = Naming.functor_name fully_abstract_tname in let distrib_lid = Located.mk ~loc Longident.(Ldot (Lident gen_module_str, "distrib")) in [ Str.module_ ~loc @@ Mb.mk ~loc (Located.mk ~loc (Some "T")) (Mod.structure ~loc [ fmap_decl ; Str.type_ ~loc Nonrecursive [ Type.mk ~loc ~params:tdecl.ptype_params ~kind:Ptype_abstract ~priv: Public ~cstrs:[] ~manifest:(Typ.constr ~loc (Located.mk ~loc @@ lident tdecl.ptype_name.txt) @@ List.map ~f:fst tdecl.ptype_params) (Located.mk ~loc "t") ]]) ; Str.module_ ~loc @@ Mb.mk ~loc (Located.mk ~loc @@ Some gen_module_str) (Mod.apply ~loc (Mod.ident ~loc (Located.mk ~loc @@ Lident (match tdecl.ptype_params with [] -> "Fmap" | xs -> sprintf "Fmap%d" (List.length xs)) )) (Mod.ident ~loc (Located.mk ~loc @@ Lident "T")) ) ] @ (List.map constructors ~f:(fun { pcd_name; pcd_args } -> let names = get_param_names pcd_args |> List.mapi ~f:(fun i _ -> sprintf "a%d" i) in let body = let constr_itself = function | [] -> Exp.construct (Located.mk ~loc @@ lident pcd_name.txt) None | args -> Exp.construct (Located.mk ~loc @@ lident pcd_name.txt) @@ Option.some @@ (match args with [x] -> x | args -> Exp.mytuple ~loc args) in match names with | [] -> constr_itself [] | [one] -> constr_itself [Exp.ident ~loc @@ Located.mk ~loc (Lident one)] | xs -> (* construct tuple here *) constr_itself (List.map ~f:(fun name -> Exp.ident ~loc @@ Located.mk ~loc (Lident name)) xs) in let body = [%expr inj [%e Exp.apply ~loc (Exp.ident ~loc distrib_lid) [nolabel, body] ] ] in Str.value ~loc Asttypes.Nonrecursive [ Vb.mk ~loc (Pat.var ~loc @@ lower_lid pcd_name) (match names with | [] -> Exp.fun_ ~loc nolabel None (Pat.construct ~loc (Located.mk ~loc (Lident "()")) None) body | names -> List.fold_right ~f:(fun name acc -> Exp.fun_ ~loc nolabel None (Pat.var ~loc @@ Located.mk ~loc name) acc) names ~init:body) ] ) ) (* At the moment we genrate fmap here but it is totally fine to reuse the one genrated by GT *) let prepare_fmap ~loc tdecl = [%stri let rec fmap _eta = GT.gmap [%e Exp.ident ~loc (Located.mk ~loc @@ lident tdecl.ptype_name.txt) ] _eta] let mangle_string s = s ^ "_ltyp" let map_deepest_lident ~f lident = let rec helper = function | Lident s -> Lident (f s) | Ldot (l, s) -> Ldot (l, f s) | Lapply (l, r) -> Lapply (l, helper r) in helper lident let mangle_lident lident = map_deepest_lident ~f:mangle_string lident let mangle_core_type typ = let rec helper typ = let loc = typ.ptyp_loc in match typ with | [%type: _] -> assert false | [%type: string] -> [%type: string logic] | _ -> match typ.ptyp_desc with | Ptyp_var s -> typ | Ptyp_constr ({txt; loc}, params) -> Typ.constr ~loc {loc; txt = mangle_lident txt} @@ List.map ~f:helper params | _ -> failwith "should not happen" in helper typ let mangle_reifier typ = let rec helper typ = let loc = typ.ptyp_loc in match typ with | [%type: _] -> assert false | [%type: string] | [%type: int] -> [%expr OCanren.reify] | _ -> match typ.ptyp_desc with | Ptyp_var s -> Exp.ident ~loc @@ Located.lident ~loc ("f" ^ s) | Ptyp_constr ({txt; loc}, params) -> Exp.apply ~loc (Exp.ident ~loc @@ Located.mk ~loc (map_deepest_lident ~f:(fun s -> s^"_reify") txt)) @@ List.map ~f:(fun typ -> Nolabel, helper typ) params | _ -> failwith "should not happen" in helper typ let revisit_adt ~loc other_attrs tdecl ctors = let der_typ_name = tdecl.ptype_name.Asttypes.txt in (* Let's forget about mutal recursion for now *) (* For every constructor argument we need to put ground types to parameters *) let mapa, full_t = List.fold_right ~f:(fun cd (n, acc_map,cs) -> let n,map2,new_args = List.fold_right ~f:(fun typ (n,map,args) -> match typ.ptyp_desc with | Ptyp_any -> assert false | Ptyp_var s -> (n, map, typ::args) | Ptyp_constr ({txt;loc}, params) -> begin match FoldInfo.param_for_rtyp typ map with | Some {FoldInfo.param_name } -> (n, map, (ptyp_var ~loc param_name)::args) | None -> (* We need to mangle whole constructor *) let ltyp = mangle_core_type typ in let new_name = sprintf "a%d" n in (n+1, FoldInfo.extend new_name typ ltyp map, (ptyp_var ~loc new_name)::args) end | _ -> match FoldInfo.param_for_rtyp typ map with | Some {FoldInfo.param_name } -> (n, map, (ptyp_var ~loc param_name)::args) | None -> let new_name = sprintf "a%d" n in (n+1, FoldInfo.extend new_name typ typ map, (ptyp_var ~loc new_name)::args) ) (match cd.pcd_args with Pcstr_tuple tt -> tt | Pcstr_record _ -> assert false) ~init:(n, acc_map,[]) in let new_args = Pcstr_tuple new_args in (n, map2, { cd with pcd_args = new_args } :: cs) ) ctors ~init:(0, FoldInfo.empty, []) |> (fun (_, mapa, cs) -> mapa, { tdecl with ptype_kind = Ptype_variant cs ; ptype_attributes = other_attrs }) in (* now we need to add some parameters if we collected ones *) let ans = if FoldInfo.is_empty mapa then let fmap_for_typ = prepare_fmap ~loc full_t in let ltyp = pstr_type ~loc Recursive [ { tdecl with ptype_kind = Ptype_abstract ; ptype_name = Located.mk ~loc (mangle_string der_typ_name) ; ptype_manifest = Some (ptyp_constr ~loc (Located.lident ~loc "logic") [ ptyp_constr ~loc (Located.lident ~loc der_typ_name) @@ List.map ~f:fst tdecl.ptype_params ]) ; ptype_attributes = other_attrs } ] in let ground_typ = pstr_type ~loc Nonrecursive [{full_t with ptype_attributes = other_attrs}] in let the_reifier = let reifiers = FoldInfo.map ~f:(fun {FoldInfo.rtyp} -> mangle_reifier rtyp) mapa in pstr_value ~loc Recursive [ value_binding ~loc ~pat:(ppat_var ~loc @@ Located.mk ~loc (der_typ_name ^ "_reify")) ~expr:[%expr fun h -> [%e pexp_apply ~loc (pexp_ident ~loc @@ Located.mk ~loc Longident.(Ldot (Lident (Naming.functor_name tdecl.ptype_name.txt), "reify"))) (List.map ~f:(fun t -> (Nolabel,t)) (reifiers @ [[%expr h]])) ] ] ] in ground_typ :: ltyp :: (prepare_distribs der_typ_name ~loc full_t fmap_for_typ) @ [the_reifier] else let functorized_type = Naming.fabst_name full_t.ptype_name.txt in let fully_abstract_typ = (* a type name for which we will generate `fmap` *) let extra_params = FoldInfo.map mapa ~f:(fun fi -> (Ast_helper.Typ.var fi.FoldInfo.param_name, (Asttypes.NoVariance, Asttypes.NoInjectivity))) in let open Location in {full_t with ptype_params = full_t.ptype_params @ extra_params; ptype_name = { full_t.ptype_name with txt = functorized_type }} in let fully_abstract_tdecl = pstr_type ~loc Nonrecursive [fully_abstract_typ] in let ground_typ = let alias = let old_params = List.map ~f:fst tdecl.ptype_params in let extra_params = FoldInfo.map ~f:(fun {FoldInfo.rtyp} -> rtyp) mapa in Typ.constr ~loc (Located.lident ~loc fully_abstract_typ.ptype_name.Asttypes.txt) (old_params @ extra_params) in pstr_type ~loc Recursive [{ tdecl with ptype_manifest = (Some alias) ; ptype_kind=Ptype_abstract ; ptype_attributes = other_attrs }] in let logic_typ = let alias = let old_params = List.map ~f:fst tdecl.ptype_params in let extra_params = FoldInfo.map ~f:(fun {FoldInfo.ltyp} -> ltyp) mapa in Typ.constr ~loc (Located.lident ~loc "logic") [ Typ.constr ~loc (Located.lident ~loc fully_abstract_typ.ptype_name.Asttypes.txt) (old_params @ extra_params) ] in pstr_type ~loc Recursive [ { tdecl with ptype_kind = Ptype_abstract ; ptype_manifest = Some alias ; ptype_name = Located.map mangle_string tdecl.ptype_name ; ptype_attributes = other_attrs } ] in let fmap_for_typ = prepare_fmap ~loc fully_abstract_typ in let distribs = prepare_distribs ~loc der_typ_name fully_abstract_typ fmap_for_typ in let the_reifier = let reifiers = FoldInfo.map ~f:(fun {FoldInfo.rtyp} -> mangle_reifier rtyp) mapa in pstr_value ~loc Recursive [ value_binding ~loc ~pat:(ppat_var ~loc @@ Located.mk ~loc (der_typ_name ^ "_reify")) ~expr:[%expr fun eta -> [%e pexp_apply ~loc (pexp_ident ~loc @@ Located.mk ~loc Longident.(Ldot (Lident (Naming.functor_name tdecl.ptype_name.txt), "reify"))) (List.map ~f:(fun t -> (Nolabel,t)) (reifiers @ [[%expr eta]])) ] ] ] in fully_abstract_tdecl :: ground_typ :: logic_typ :: distribs @ [the_reifier] in ans let has_to_gen_attr (xs: attributes) = let ours,others = List.partition_map xs ~f:(fun ({attr_name={txt};_} as attr) -> if String.equal txt "distrib" then First attr else Second attr ) in assert (List.length ours <= 1); match ours with | [] -> None | [h] -> Some (h, others) | _ -> failwith "to many distrib attributes" let suitable_tydecl_wrap ~on_ok ~on_fail tdecl = match tdecl.ptype_kind with | Ptype_variant cs when Option.is_none tdecl.ptype_manifest -> begin match has_to_gen_attr tdecl.ptype_attributes with | None -> on_fail () | Some (our, other_attrs) -> Attribute.explicitly_drop#type_declaration tdecl; on_ok cs other_attrs { tdecl with ptype_attributes = [] } end | _ -> on_fail () let suitable_tydecl = suitable_tydecl_wrap ~on_ok:(fun _ _ _ -> true) ~on_fail:(fun () -> false) let str_type_decl ~loc (flg,tdls) = let wrap_tydecls loc ts = let f tdecl = suitable_tydecl_wrap tdecl ~on_ok:(fun cs other_attrs tdecl -> revisit_adt ~loc other_attrs tdecl cs) ~on_fail:(fun () -> failwith "Only variant types without manifest are supported") in List.concat (List.map ~f ts) in wrap_tydecls loc tdls
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>