Skip to content

Commit ce3aafb

Browse files
committed
feat: implement prolog solution
1 parent 31504ce commit ce3aafb

File tree

4 files changed

+89
-56
lines changed

4 files changed

+89
-56
lines changed

src/main/scala/io/github/kelvindev15/prolog/engine/PrologEngine.scala

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package io.github.kelvindev15.prolog.engine
2+
3+
import io.github.kelvindev15.prolog.PrologProgram
4+
import io.github.kelvindev15.prolog.core.{Struct, Term, Variable}
5+
import io.github.kelvindev15.prolog.core.Theory.Theory
6+
import io.github.kelvindev15.prolog.engine.Solver.Solution
7+
import io.github.kelvindev15.prolog.engine.Solver.Solution.{Halt, Yes}
8+
import io.github.kelvindev15.prolog.engine.visitors.{BackVisitor, TuPKtTermVisitor}
9+
import it.unibo.tuprolog.core.{Clause as KClause, Struct as KStruct, Substitution as KSubstitution, Term as KTerm}
10+
import it.unibo.tuprolog.solve.Solver as KSolver
11+
import it.unibo.tuprolog.solve.channel.{InputStore, OutputStore}
12+
import it.unibo.tuprolog.solve.classic.ClassicSolverFactory
13+
import it.unibo.tuprolog.solve.flags.FlagStore
14+
import it.unibo.tuprolog.theory.Theory as KTheory
15+
import it.unibo.tuprolog.unify.Unificator
16+
import it.unibo.tuprolog.solve.Solution as KSolution
17+
18+
trait Solver:
19+
def solve(program: PrologProgram): Iterator[Solution]
20+
21+
import scala.jdk.CollectionConverters.*
22+
23+
object Solver:
24+
type Substitution = Map[Variable, Term]
25+
enum Solution:
26+
case Yes(query: Struct, substitution: Substitution)
27+
case No(query: Struct)
28+
case Halt
29+
30+
private val visitor = TuPKtTermVisitor()
31+
private val back = BackVisitor()
32+
given Conversion[Term, KTerm] = _.accept(visitor)
33+
given Conversion[KTerm, KClause] = _.asClause()
34+
given Conversion[KTerm, KStruct] = _.asStruct()
35+
given Conversion[Theory, KTheory] with
36+
override def apply(theory: Theory): KTheory = KTheory.of(theory.map(_.asClause()) *)
37+
given Conversion[KStruct, Struct] = back.visitStruct(_)
38+
given Conversion[KSubstitution, Substitution] = {
39+
case substitution: KSubstitution.Unifier => Map(
40+
substitution.asScala.toSeq.map(p => (back.visitVar(p._1), back.visitTerm(p._2)))*
41+
)
42+
}
43+
given Conversion[KSolution, Solution] = {
44+
case yes: KSolution.Yes => Yes(yes.getQuery, yes.getSubstitution)
45+
case no: KSolution.No => Solution.No(no.getQuery)
46+
case halt: KSolution.Halt => Halt
47+
}
48+
given Conversion[java.util.Iterator[KSolution], Iterator[Solution]] = _.asScala.map(identity)
49+
50+
private def tuPrologClassicSolverOf(staticTheory: Theory, dynamicTheory: Theory): KSolver =
51+
ClassicSolverFactory.INSTANCE.solverOf(
52+
Unificator.getDefault,
53+
ClassicSolverFactory.INSTANCE.getDefaultRuntime,
54+
FlagStore.DEFAULT,
55+
staticTheory,
56+
dynamicTheory,
57+
InputStore.fromStandard(),
58+
OutputStore.fromStandard()
59+
)
60+
61+
def tuPrologSolver(): Solver = (program: PrologProgram) =>
62+
val solver = tuPrologClassicSolverOf(program.dynamicTheory, program.staticTheory)
63+
program.goal.map { goal => solver.solve(goal.asStruct()).iterator() }.get
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.github.kelvindev15.prolog.engine.visitors
2+
3+
import io.github.kelvindev15.prolog.core.Constant.Atom
4+
import io.github.kelvindev15.prolog.core.{Struct, Term, Variable}
5+
import it.unibo.tuprolog.core
6+
import it.unibo.tuprolog.core.{TermVisitor, Atom as KAtom, Struct as KStruct, Term as KTerm, Var as KVariable}
7+
8+
import scala.jdk.CollectionConverters.*
9+
10+
class BackVisitor extends TermVisitor[Term]:
11+
override def defaultValue(term: KTerm): Term = term match
12+
case atom: KAtom => visitAtom(atom)
13+
case variable: KVariable => visitVar(variable)
14+
15+
override def visitAtom(term: KAtom): Atom = Atom(term.getValue)
16+
override def visitStruct(term: KStruct): Struct =
17+
Struct(Atom(term.getFunctor), term.getArgs.asScala.map(visitTerm).toSeq*)
18+
override def visitVar(term: KVariable): Variable = Variable(term.getName)
19+
20+
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package io.github.kelvindev15.engine
22

33
import io.github.kelvindev15.prolog.dsl.{DeclarativeDSL, PrologDSL}
4-
import io.github.kelvindev15.prolog.engine.PrologEngine.Solution
4+
import io.github.kelvindev15.prolog.engine.Solver.Solution
55
import io.github.kelvindev15.prolog.engine.Solver
66
import org.scalatest.flatspec.AnyFlatSpec
77
import org.scalatest.matchers.should.Matchers
88

99
class TestPrologEngine extends AnyFlatSpec with Matchers with PrologDSL with DeclarativeDSL:
1010

1111
"A prolog with no solution" should "return a single NO answer" in:
12-
val solution = Solver.solve {
12+
val solution = Solver.tuPrologSolver().solve {
1313
prolog {
1414
staticTheory {
1515
clause { "father"("mala", "paga") }
@@ -18,4 +18,7 @@ class TestPrologEngine extends AnyFlatSpec with Matchers with PrologDSL with Dec
1818
solve { "father"("mala", X) }
1919
}
2020
}
21-
solution shouldBe a [Solution]
21+
solution shouldBe a [Iterator[Solution]]
22+
for
23+
s <- solution
24+
do println(s)

0 commit comments

Comments
 (0)