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
|
type step =
| Type of string
| Poly
| Any
| Arrow_left
| Arrow_right
| Product of
{ pos : int
; length : int
}
| Argument of
{ pos : int
; length : int
}
module Sign = Db.Type_polarity.Sign
type t = step list list
let rev_concat lst = List.fold_left (fun acc xs -> List.rev_append xs acc) [] lst
let rec paths_of_type ~prefix t =
match t with
| Db.Typexpr.Poly _ -> [ Poly :: prefix ]
| Any -> [ Any :: prefix ]
| Arrow (a, b) ->
let prefix_left = Arrow_left :: prefix in
let prefix_right = Arrow_right :: prefix in
List.rev_append
(paths_of_type ~prefix:prefix_left a)
(paths_of_type ~prefix:prefix_right b)
| Constr (name, args) ->
let prefix = Type name :: prefix in
begin
match args with
| [] -> [ prefix ]
| _ ->
let length = List.length args in
rev_concat
@@ List.mapi
(fun i arg ->
let prefix = Argument { pos = i; length } :: prefix in
paths_of_type ~prefix arg)
args
end
| Tuple args ->
let length = List.length args in
rev_concat
@@ List.mapi (fun i arg ->
let prefix = Product { pos = i; length } :: prefix in
paths_of_type ~prefix arg)
@@ args
| Unhandled -> []
let paths_of_type t = List.map List.rev @@ paths_of_type ~prefix:[] t
(* *)
let skip_entry _ = 10
let distance xs ys =
let len_xs = List.length xs in
let len_ys = List.length ys in
let cache = Array.make_matrix (1 + len_xs) (1 + len_ys) (-1) in
let inv = Db.Type_polarity.Sign.not in
let rec memo ~xsgn ~ysgn i j xs ys =
let r = cache.(i).(j) in
if r >= 0
then r
else begin
let r = go ~xsgn ~ysgn i j xs ys in
cache.(i).(j) <- r ;
r
end
and go ~xsgn ~ysgn i j xs ys =
match xs, ys with
| [], [] -> 0
| [], _ -> 0
| [ Any ], _ when xsgn = ysgn -> 0
| [ Poly ], [ (Any | Poly) ] when xsgn = ysgn -> 0
| Arrow_left :: xs, Arrow_left :: ys ->
memo ~xsgn:(inv xsgn) ~ysgn:(inv ysgn) (i + 1) (j + 1) xs ys
| x :: xs, y :: ys when x = y && xsgn = ysgn -> memo ~xsgn ~ysgn (i + 1) (j + 1) xs ys
| _, Arrow_left :: ys -> 1 + memo ~xsgn ~ysgn:(inv ysgn) i (j + 1) xs ys
| Arrow_left :: xs, _ -> 1 + memo ~xsgn:(inv xsgn) ~ysgn (i + 1) j xs ys
| _, Arrow_right :: ys -> memo ~xsgn ~ysgn i (j + 1) xs ys
| Arrow_right :: xs, _ -> memo ~xsgn ~ysgn (i + 1) j xs ys
| _, [] -> 10_000
| Product _ :: xs, Product _ :: ys -> 1 + memo ~xsgn ~ysgn (i + 1) (j + 1) xs ys
| Argument _ :: xs, Argument _ :: ys -> 1 + memo ~xsgn ~ysgn (i + 1) (j + 1) xs ys
| Product _ :: xs, ys -> 1 + memo ~xsgn ~ysgn (i + 1) j xs ys
| xs, Product _ :: ys -> 1 + memo ~xsgn ~ysgn i (j + 1) xs ys
| Type x :: xs', Type y :: ys' when xsgn = ysgn -> begin
let skip_y = skip_entry y in
match Name_cost.best_match ~sub:x y with
| None -> skip_y + memo ~xsgn ~ysgn i (j + 1) xs ys'
| Some (_, cost) -> (cost / 3) + memo ~xsgn ~ysgn (i + 1) (j + 1) xs' ys'
end
| xs, Type y :: ys' -> skip_entry y + memo ~xsgn ~ysgn i (j + 1) xs ys'
| xs, Argument _ :: ys' -> memo ~xsgn ~ysgn i (j + 1) xs ys'
| _, (Any | Poly) :: _ -> 10_000
in
let pos = Db.Type_polarity.Sign.Pos in
go ~xsgn:pos ~ysgn:pos 0 0 xs ys
let minimize = function
| [] -> 0
| arr ->
let used = Array.make (List.length (List.hd arr)) false in
let arr =
Array.map (fun lst ->
let lst = List.mapi (fun i x -> x, i) lst in
List.sort Stdlib.compare lst)
@@ Array.of_list arr
in
Array.sort (fun xs ys -> Stdlib.compare xs ys) arr ;
let heuristics = Array.make (Array.length arr + 1) 0 in
for i = Array.length heuristics - 2 downto 0 do
let best = fst (List.hd arr.(i)) in
heuristics.(i) <- heuristics.(i + 1) + best
done ;
let best = ref 1000 in
let limit = ref 0 in
let rec go rem acc i =
incr limit ;
if !limit > 10_000
then false
else if rem <= 0
then begin
(* entry type is smaller than query type *)
let score = acc + (1000 * (Array.length arr - i)) in
best := min score !best ;
true
end
else if i >= Array.length arr
then begin
(* query type is smaller than entry type *)
let score = acc + (5 * rem) in
best := min score !best ;
true
end
else if acc + heuristics.(i) >= !best
then true
else begin
let rec find = function
| [] -> true
| (cost, j) :: rest ->
let continue =
if used.(j)
then true
else begin
used.(j) <- true ;
let continue = go (rem - 1) (acc + cost) (i + 1) in
used.(j) <- false ;
continue
end
in
if continue then find rest else false
in
find arr.(i)
end
in
let _ = go (Array.length used) 0 0 in
!best
let v ~query_paths ~entry =
let entry_paths = paths_of_type entry in
match entry_paths, query_paths with
| _, [] | [], _ -> 0
| _ ->
let arr = List.map (fun p -> List.map (distance p) entry_paths) query_paths in
minimize arr
|