anchor.diff:                    | _ -> false) -> None
   
   module RuleSet =
  -  type RuleSet = HashEqMap<obj, TyTree<Rule<Type>>>
  -
  -  let getInferenceRules (ty: Type) =
  +  type RuleSet = {rules: HashEqMap<Type, array<Rule<Type>>>; tree: TyTree<Rule<Type>>}
  +
  +  let hasInferenceRules (ty: Type) =
       ty.GetCustomAttributes<InferenceRules> true
  -    |> Seq.tryPick Some
  -
  -  let preprocess infRules =
  +    |> Seq.isEmpty
  +    |> not
  +
  +  let collectRules o =
       let rec collectRules ty =
  -      match getInferenceRules ty with
  -       | None -> Seq.empty
  -       | Some _ ->
  -         [ty.GetMethods BindingFlags.PublicDeclaredInstance
  -          |> Seq.map (fun infRule ->
  -             RuleMethod (infRule, infRules) :> Rule<_>)
  -          collectRules ty.BaseType]
  -         |> Seq.concat
  -    infRules.GetType ()
  +      if hasInferenceRules ty then
  +        [ty.GetMethods BindingFlags.PublicDeclaredInstance
  +         |> Seq.map (fun infRule ->
  +            RuleMethod (infRule, o) :> Rule<_>)
  +         collectRules ty.BaseType]
  +        |> Seq.concat
  +      else
  +        Seq.empty
  +    o.GetType ()
       |> collectRules
  -    |> Seq.map (fun rule -> (rule.ReturnType, rule))
  -    |> TyTree.build
  -
  -  let ofSeq infRules : RuleSet =
  -    infRules
  -    |> Seq.fold
  -        (fun rulesMap rules ->
  -          HashEqMap.add
  -           rules
  -           (preprocess rules)
  -           rulesMap)
  -        HashEqMap.empty
  -
  -  let rulesFor (infRuleSet: RuleSet) (desiredTy: Ty<_>) = seq {
  -    yield! HashEqMap.toSeq infRuleSet
  -           |> Seq.collect (fun (_, infRulesTree) ->
  -              TyTree.filter infRulesTree desiredTy)
  +
  +  let empty = {rules = HashEqMap.empty; tree = TyTree.build []}
  +
  +  let maybeAddRules (o: obj) ruleSet =
  +    match o with
  +     | null ->
  +       ruleSet
  +     | o ->
  +       let t = o.GetType ()
  +       if hasInferenceRules t
  +          && HashEqMap.tryFind t ruleSet.rules |> Option.isNone
  +       then let rules = HashEqMap.add t (collectRules o |> Seq.toArray) ruleSet.rules
  +            {rules = rules
  +             tree = lazy (rules
  +                          |> HashEqMap.toSeq
  +                          |> Seq.collect (fun (_, rules) ->
  +                             rules
  +                             |> Seq.map (fun rule -> (rule.ReturnType, rule)))
  +                          |> TyTree.build
  +                          |> force)}
  +       else ruleSet
  +
  +  let rulesFor (ruleSet: RuleSet) (desiredTy: Ty<_>) = seq {
  +    yield! TyTree.filter ruleSet.tree desiredTy
       match Ty.toMonoType desiredTy with
        | None -> ()
        | Some t ->
  
positive.code: 
    let tryGenerate (rules: obj) : option<'a> =
      let desTy = typeof<'a> |> Ty.ofType |> mapVars (Fresh.newMapper ())
      let rules = RuleSet.ofSeq [rules]
      seq {1 .. Int32.MaxValue}
      |> Seq.tryPick (fun limit ->
         tryGenerate' limit rules HashEqMap.empty HashEqMap.empty [] desTy
  
negative.code:                       then t.GetGenericTypeDefinition().MakeGenericType(genArgTys)
                        else t).GetConstructor([||]).Invoke [||] |> Some}
    }
  
  /////////////////////////////////////////////////////////////////////////
  
  