/// <summary> /// Queries a solver for a goal /// </summary> public static IQueryResult Query(this ISolver solver, ILiteral goal) { // Result is false for something without a key if (goal.UnificationKey == null) { return new BasicQueryResult(false, new EmptyBinding(null)); } // Compile the query var unifier = new SimpleUnifier(); var assignments = new PredicateAssignmentList(); // Assume we have a basic predicate foreach (var arg in goal.Dependencies) { assignments.AddArgument(arg); } // Run through the unifier var freeVariableNames = unifier.QueryUnifier.Bind(assignments.Assignments); var freeVariables = freeVariableNames.Select(variable => unifier.GetVariableLocation(variable).Dereference()); unifier.QueryUnifier.Compile(assignments.Assignments); // Call via the solver var moveNext = solver.Call(goal.UnificationKey, unifier.GetArgumentVariables(assignments.CountArguments())); Func<IQueryResult> nextResult = () => { // Update the variables to the next result var succeeded = moveNext(); // Nothing to do if we didn't succeed if (!succeeded) { return new BasicQueryResult(false, new EmptyBinding(null)); } // Bind the variables var variableValues = freeVariables .Select(varRef => varRef.Freeze()) .Zip(freeVariableNames, (value, name) => new { Value = value, Name = name }).ToArray(); var binding = new BasicBinding(null, variableValues.ToDictionary(val => val.Name, val => val.Value)); // Return the result return new BasicQueryResult(true, binding); }; // Chain to produce the final result return new ChainedResult(nextResult(), () => Task.FromResult(nextResult())); }
public void FunctorUnifiesWithBindings() { var tA = Literal.NewFunctor(1); var vX = Literal.NewVariable(); var vY = Literal.NewVariable(); var aX = Literal.NewAtom(); var aOfX = tA.With(vX); // a(x) var aOfY = tA.With(vY); // a(Y) var bindings = new BasicBinding(aX, new[] { new { var = vX, val = aX} }.ToDictionary(item => item.var, item => item.val)); var unified = aOfY.Unify(aOfX, bindings); Assert.IsNotNull(unified); Assert.AreEqual(aX, unified.GetValueForVariable(vY)); }