@@ -11,8 +11,9 @@ where
12import Prelude
12import Prelude
14−import Docs.Search.TypeDecoder
15import Docs.Search.Config
14import Docs.Search.Config
15+import Docs.Search.DocsJson
16+import Docs.Search.TypeDecoder
17import Control.Alt ((<|>))
18import Control.Alt ((<|>))
18import Data.Array as Array
19import Data.Array as Array
@@ -183,20 +184,24 @@ data Substitution
183 | Match String String
184 | Match String String
184 | Generalize TypeQuery String
185 | Generalize TypeQuery String
185 | Substitute String String
186 | Substitute String String
186− | MatchConstraints String String
187+ | MatchConstraints (Set String) (Set String)
187 | MissingConstraint
188 | MissingConstraint
188 | ExcessiveConstraint
189 | ExcessiveConstraint
190+ | RowsMismatch Int Int
190derive instance genericSubstitution :: Generic Substitution _
193derive instance genericSubstitution :: Generic Substitution _
192instance showSubstitution :: Show Substitution where
195instance showSubstitution :: Show Substitution where
193 show x = genericShow x
196 show x = genericShow x
195−unify :: TypeQuery -> Type -> Maybe (List Substitution)
198+unify :: TypeQuery -> Type -> List Substitution
196unify query type_ = go Nil (List.singleton { q: query, t: type_ })
199unify query type_ = go Nil (List.singleton { q: query, t: type_ })
198− go :: List Substitution -> List { q :: TypeQuery, t :: Type } -> Maybe (List Substitution)
201+ go :: List Substitution -> List { q :: TypeQuery, t :: Type } -> List Substitution
199− go acc Nil = Just acc
202+ go acc Nil = acc
203+ go acc ({ q, t: ParensInType t } : rest) =
204+ go acc ({ q, t } : rest)
201 -- * ForAll
206 -- * ForAll
202 go acc ({ q: (QForAll queryBinders q), t:type_1@(ForAll _ _ _) } : rest) =
207 go acc ({ q: (QForAll queryBinders q), t:type_1@(ForAll _ _ _) } : rest) =
@@ -218,6 +223,16 @@ unify query type_ = go Nil (List.singleton { q: query, t: type_ })
218 -- * Names
223 -- * Names
219 go acc ({ q: QConst qname, t: TypeConstructor (QualifiedName { name }) } : rest) =
224 go acc ({ q: QConst qname, t: TypeConstructor (QualifiedName { name }) } : rest) =
220 go (Match qname name : acc) rest
225 go (Match qname name : acc) rest
226+ go acc ({ q: QConst qname, t } : rest) =
227+ go (Mismatch : acc) rest
228+ go acc ({ q, t: TypeConstructor (QualifiedName { name }) } : rest) =
229+ go (Mismatch : acc) rest
231+ -- type operators can't appear in type queries: this is always a mismatch
232+ go acc ({ q, t: TypeOp (QualifiedName { name }) } : rest) =
233+ go (Mismatch : acc) rest
234+ go acc ({ q, t: BinaryNoParensType _ _ _ } : rest) =
235+ go (Mismatch : acc) rest
222 -- * Functions
237 -- * Functions
223 go acc ({ q: QFun q1 q2
238 go acc ({ q: QFun q1 q2
@@ -225,17 +240,20 @@ unify query type_ = go Nil (List.singleton { q: query, t: type_ })
225 (QualifiedName { moduleName: [ "Prim" ]
240 (QualifiedName { moduleName: [ "Prim" ]
226 , name: "Function" })) t1) t2 } : rest) =
241 , name: "Function" })) t1) t2 } : rest) =
227 go acc ({ q: q1, t: t1 } : { q: q2, t: t2 } : rest)
242 go acc ({ q: q1, t: t1 } : { q: q2, t: t2 } : rest)
243+ go acc ({ q: QFun q1 q2, t } : rest) =
244+ go (Mismatch : acc) rest
229 -- * Constraints
246 -- * Constraints
230− go acc ({ q: QConstraint className args q
247+ go acc ({ q: q@(QConstraint _ _ _)
231− , t: ConstrainedType cnstr t } : rest) =
248+ , t: t@(ConstrainedType _ _) } : rest) =
249+ let qcs = Set.fromFoldable (joinQueryConstraints q).constraints
250+ tcs = Set.fromFoldable (joinConstraints t).constraints
252+ -- TODO: use edit distance instead
232− go (MatchConstraints className typeClassName : acc) ({ q, t } : rest)
253+ go (MatchConstraints qcs tcs : acc) rest
233− where typeClassName = (unwrap (unwrap cnstr).constraintClass).name
234− go acc ({ q: QConstraint _ _ q
254+ go acc ({ q: QConstraint _ _ q, t } : rest) =
236 go (ExcessiveConstraint : acc) ({ q, t } : rest)
255 go (ExcessiveConstraint : acc) ({ q, t } : rest)
238− , t: ConstrainedType cnstr t } : rest) =
256+ go acc ({ q, t: ConstrainedType _ t } : rest) =
239 go (MissingConstraint : acc) ({ q, t } : rest)
257 go (MissingConstraint : acc) ({ q, t } : rest)
241 -- * Rows
259 -- * Rows
@@ -243,25 +261,45 @@ unify query type_ = go Nil (List.singleton { q: query, t: type_ })
243 , t: TypeApp (TypeConstructor
261 , t: TypeApp (TypeConstructor
244 (QualifiedName { moduleName: [ "Prim" ]
262 (QualifiedName { moduleName: [ "Prim" ]
245 , name: "Record" })) row } : rest) =
263 , name: "Record" })) row } : rest) =
246− let { rows, ty } = joinRows row in
264+ let { rows, ty } = joinRows row
247− if List.length rows == List.length qRows then
265+ qRowsLength = List.length qRows
266+ rowsLength = List.length rows in
267+ if rowsLength == qRowsLength then
249 sortedQRows = List.sortBy (\x y -> compare (fst x) (fst y)) qRows
269 sortedQRows = List.sortBy (\x y -> compare (fst x) (fst y)) qRows
250 sortedRows = List.sortBy (\x y -> compare x.row y.row) rows in
270 sortedRows = List.sortBy (\x y -> compare x.row y.row) rows in
273+ (List.zipWith (\(Tuple qRowName _) { row: rowName } ->
274+ Match qRowName rowName) sortedQRows sortedRows <> acc)
276+ (List.zipWith (\(Tuple _ q) { ty: t } ->
252− (List.zipWith (\(Tuple _ q) { ty: t } -> { q, t }) sortedQRows sortedRows <> rest)
277+ { q, t }) sortedQRows sortedRows <> rest)
254− Nothing
279+ go (RowsMismatch qRowsLength rowsLength : acc) rest
281+ go acc ({ q: QRow _ } : rest) =
282+ go (Mismatch : acc) rest
256 -- * Type application
284 -- * Type application
257 go acc ({ q: QApp q1 q2, t: TypeApp t1 t2 } : rest) =
285 go acc ({ q: QApp q1 q2, t: TypeApp t1 t2 } : rest) =
258 go acc ({ q: q1, t: t1 } : { q: q2, t: t2 } : rest)
286 go acc ({ q: q1, t: t1 } : { q: q2, t: t2 } : rest)
260− go acc _ = Nothing
288+ go acc ({ q, t: TypeLevelString _ } : rest) =
289+ go (Mismatch : acc) rest
291+ go acc ({ q, t: TypeWildcard } : rest) =
292+ go (Mismatch : acc) rest
294+ go acc ({ q, t: RCons _ _ _ } : rest) =
295+ go (Mismatch : acc) rest
297+ go acc ({ q, t: REmpty } : rest) =
298+ go (Mismatch : acc) rest
262−penalty :: TypeQuery -> Type -> Maybe Int
300+penalty :: TypeQuery -> Type -> Int
263penalty typeQuery ty =
301penalty typeQuery ty =
264− unify typeQuery ty <#> \substs ->
302+ let substs = unify typeQuery ty in
265 typeVarPenalty substs * config.penalties.typeVars +
303 typeVarPenalty substs * config.penalties.typeVars +
266 namesPenalty substs +
304 namesPenalty substs +
267 mismatchPenalty substs
305 mismatchPenalty substs
@@ -293,14 +331,17 @@ typeVarPenalty substs =
293namesPenalty :: List Substitution -> Int
331namesPenalty :: List Substitution -> Int
294namesPenalty = go 0
332namesPenalty = go 0
296− go n Nil = n
334+ go p Nil = p
335+ go p (Mismatch : rest) = go (p + config.penalties.mismatch) rest
297− go n (Match a b : rest)
336+ go p (Match a b : rest)
298− | a == b = go n rest
337+ | a == b = go p rest
299− | otherwise = go (n + config.penalties.match) rest
338+ | otherwise = go (p + config.penalties.match) rest
300− go n (MatchConstraints a b : rest)
339+ go p (MatchConstraints qcs tcs : rest)
301− | a == b = go n rest
340+ = let p' = Set.size (Set.union qcs tcs) -
341+ Set.size (Set.intersection qcs tcs) in
302− | otherwise = go (n + config.penalties.matchConstraint) rest
342+ go (p + config.penalties.matchConstraint * p') rest
343+ go p (RowsMismatch n m : rest) = go (config.penalties.rowsMismatch * abs (n - m)) rest
303− go n (_ : rest) = go n rest
344+ go p (_ : rest) = go p rest
305-- | Penalty for generalization and instantiation.
346-- | Penalty for generalization and instantiation.
306mismatchPenalty :: List Substitution -> Int
347mismatchPenalty :: List Substitution -> Int
@@ -312,3 +353,12 @@ mismatchPenalty = go 0
312 go n (ExcessiveConstraint : rest) = go (n + config.penalties.excessiveConstraint) rest
353 go n (ExcessiveConstraint : rest) = go (n + config.penalties.excessiveConstraint) rest
313 go n (MissingConstraint : rest) = go (n + config.penalties.missingConstraint) rest
354 go n (MissingConstraint : rest) = go (n + config.penalties.missingConstraint) rest
314 go n (_ : rest) = go n rest
355 go n (_ : rest) = go n rest
357+-- | Only returns a list of type class names (lists of arguments are omitted).
358+joinQueryConstraints :: TypeQuery -> { constraints :: List String
360+joinQueryConstraints = go Nil
362+ go acc (QConstraint name _ query) =
363+ go (name : acc) query
364+ go acc ty = { constraints: List.sort acc, ty }