@@ -6,6 +6,8 @@ import io.github.kelvindev15.prolog.solver.Solver.Solution
6
6
import io .github .kelvindev15 .prolog .solver .Solver .Solution .{Halt , Yes }
7
7
import io .github .kelvindev15 .prolog .solver .tuprolog .TuPrologClassicSolver
8
8
9
+ import scala .reflect .ClassTag
10
+
9
11
/** Instances of this trait solve [[PrologProgram ]]s. */
10
12
trait Solver :
11
13
@@ -25,7 +27,8 @@ trait Solver:
25
27
* @return
26
28
* a lazy list of the program's [[Solution ]]s.
27
29
*/
28
- def lazySolve (program : PrologProgram ): LazyList [Solution ] = solve(program).to(LazyList )
30
+ def lazySolve (program : PrologProgram ): LazyList [Solution ] =
31
+ solve(program).to(LazyList )
29
32
30
33
/** Solves a program.
31
34
*
@@ -34,12 +37,27 @@ trait Solver:
34
37
* @return
35
38
* a list of the program's [[Solution ]]s.
36
39
*/
37
- def solutionsOf (program : PrologProgram ): Seq [Solution ] = solve(program).to(Seq )
40
+ def solutionsOf (program : PrologProgram ): Seq [Solution ] =
41
+ solve(program).to(Seq )
38
42
39
- def admitsSolutions (program : PrologProgram ): Boolean =
43
+ /** Returns true if the program admits at least one solution.
44
+ *
45
+ * @param program
46
+ * the program to solve.
47
+ */
48
+ def hasSolutionFor (program : PrologProgram ): Boolean =
40
49
val solutions = solve(program)
41
50
solutions.hasNext && solutions.next().isInstanceOf [Solution .Yes ]
42
51
52
+ /** Returns true if the provided goal admits at least one solution.
53
+ *
54
+ * @param goal
55
+ * the program to satisfy.
56
+ */
57
+ def hasSolutionFor (goal : Term ): Boolean =
58
+ val solutions = solve(PrologProgram .emptyTheory withGoal goal)
59
+ solutions.hasNext && solutions.next().isInstanceOf [Solution .Yes ]
60
+
43
61
object Solver :
44
62
/** A mapping from [[Variable ]]s to [[Term ]]s */
45
63
type Substitution = Map [Variable , Term ]
@@ -64,6 +82,52 @@ object Solver:
64
82
*/
65
83
case Halt (exception : Exception )
66
84
85
+ extension (solution : Solution )
86
+ def apply (variable : Variable ): Option [Term ] = solution match
87
+ case y : Solution .Yes => Some (y.substitution(variable))
88
+ case _ => None
89
+
90
+ /** Returns true if the solution is a [[Yes ]]. */
91
+ def isYes : Boolean = solution.isInstanceOf [Solution .Yes ]
92
+
93
+ /** Returns true if the solution is a [[No ]]. */
94
+ def isNo : Boolean = solution.isInstanceOf [Solution .No ]
95
+
96
+ /** Returns true if the solution is a [[Halt ]]. */
97
+ def isHalt : Boolean = solution.isInstanceOf [Solution .Halt ]
98
+
99
+ /** Cast the solution to a [[Solution ]] of type [[T ]].
100
+ *
101
+ * @tparam T
102
+ * the type of the expected solution
103
+ *
104
+ * @throws ClassCastException
105
+ * if [[T ]] is not the runtime type of the solution.
106
+ */
107
+ def as [T <: Solution ](using ClassTag [T ]): Solution =
108
+ solution.asInstanceOf [T ]
109
+
110
+ /** Cast the solution to a [[Yes ]] [[Solution ]].
111
+ *
112
+ * @throws ClassCastException
113
+ * if [[Yes ]] is not the runtime type of the solution.
114
+ */
115
+ def asYes : Solution = solution.as[Solution .Yes ]
116
+
117
+ /** Cast the solution to a [[No ]] [[Solution ]].
118
+ *
119
+ * @throws ClassCastException
120
+ * if [[No ]] is not the runtime type of the solution.
121
+ */
122
+ def asNo : Solution = solution.as[Solution .No ]
123
+
124
+ /** Cast the solution to a [[Halt ]] [[Solution ]].
125
+ *
126
+ * @throws ClassCastException
127
+ * if [[Halt ]] is not the runtime type of the solution.
128
+ */
129
+ def asHalt : Solution = solution.as[Solution .Halt ]
130
+
67
131
/** Returns a Solver that leverages on the tuProlog engine. */
68
132
def tuPrologSolver (): Solver = TuPrologClassicSolver ()
69
133
@@ -147,22 +211,26 @@ object Solver:
147
211
): LazyList [Solution ] =
148
212
solver lazySolve (PrologProgram .emptyTheory withGoal query)
149
213
150
- /** Returns true if the program admits at least one solution.
151
- *
152
- * @param solver the solver that should be used.
153
- * @param program the program to solve.
154
- */
214
+ /** Returns true if the program admits at least one solution. If not specified
215
+ * the default solver that will be used is the [[TuPrologClassicSolver ]].
216
+ *
217
+ * @param solver
218
+ * the solver that should be used.
219
+ * @param program
220
+ * the program to solve.
221
+ */
155
222
def hasSolutionForProgram (using solver : Solver = tuPrologSolver())(
156
- program : PrologProgram
157
- ): Boolean =
158
- val solutions = solve(program)
159
- solutions.hasNext && solutions.next().isInstanceOf [Solution .Yes ]
223
+ program : PrologProgram
224
+ ): Boolean = solver hasSolutionFor program
160
225
161
- /** Returns true if the program admits at least one solution.
162
- *
163
- * @param solver the solver that should be used.
164
- * @param goal the program to satisfy.
165
- */
226
+ /** Returns true if the provided goal admits at least one solution. If not
227
+ * specified the default solver that will be used is the
228
+ * [[TuPrologClassicSolver ]].
229
+ * @param solver
230
+ * the solver that should be used.
231
+ * @param goal
232
+ * the program to satisfy.
233
+ */
166
234
def hasSolutionForGoal (using solver : Solver = tuPrologSolver())(
167
- goal : Term
168
- ): Boolean = hasSolutionForProgram( PrologProgram .emptyTheory withGoal goal)
235
+ goal : Term
236
+ ): Boolean = solver hasSolutionFor goal
0 commit comments