Retract
This commit is contained in:
parent
80fb3d1e60
commit
5bfa1691dd
10 changed files with 276 additions and 17 deletions
|
@ -1,5 +1,4 @@
|
|||
import com.xenomachina.argparser.ArgParser
|
||||
import com.xenomachina.argparser.mainBody
|
||||
import interpreter.FileLoader
|
||||
import io.GhentPrologArgParser
|
||||
import io.Logger
|
||||
|
|
|
@ -92,6 +92,7 @@ open class Preprocessor {
|
|||
term.functor == "between/3" && args.all { it is Expression } -> Between(args[0] as Expression, args[1] as Expression, args[2] as Expression)
|
||||
|
||||
// Database
|
||||
term.functor == "retract/1" -> Retract(args[0])
|
||||
term.functor == "assert/1" -> {
|
||||
if (args[0] is Rule) {
|
||||
Assert(args[0] as Rule)
|
||||
|
@ -99,7 +100,20 @@ open class Preprocessor {
|
|||
Assert(Fact(args[0] as Head))
|
||||
}
|
||||
}
|
||||
term.functor == "asserta/1" -> AssertA(args[0] as Clause)
|
||||
term.functor == "asserta/1" -> {
|
||||
if (args[0] is Rule) {
|
||||
AssertA(args[0] as Rule)
|
||||
} else {
|
||||
AssertA(Fact(args[0] as Head))
|
||||
}
|
||||
}
|
||||
term.functor == "assertz/1" -> {
|
||||
if (args[0] is Rule) {
|
||||
AssertZ(args[0] as Rule)
|
||||
} else {
|
||||
AssertZ(Fact(args[0] as Head))
|
||||
}
|
||||
}
|
||||
|
||||
// Other
|
||||
term.functor == "write/1" -> Write(args[0])
|
||||
|
|
|
@ -13,7 +13,7 @@ import prolog.ast.terms.Goal
|
|||
*/
|
||||
object Program : Resolvent {
|
||||
val internalDb = Database("")
|
||||
private val databases: MutableList<Database> = mutableListOf(internalDb)
|
||||
val databases: MutableList<Database> = mutableListOf(internalDb)
|
||||
|
||||
var storeNewLine: Boolean = false
|
||||
var variableRenamingStart: Int = 0
|
||||
|
|
|
@ -8,4 +8,4 @@ abstract class Substitution(val from: Term, val to: Term) {
|
|||
}
|
||||
typealias Substitutions = Map<Term, Term>
|
||||
typealias Answer = Result<Substitutions>
|
||||
typealias Answers = Sequence<Answer>
|
||||
typealias Answers = Sequence<Answer>
|
||||
|
|
|
@ -8,6 +8,11 @@ import prolog.ast.terms.Structure
|
|||
import prolog.ast.logic.Predicate
|
||||
import prolog.Program
|
||||
import prolog.ast.terms.Functor
|
||||
import prolog.ast.terms.Term
|
||||
import prolog.ast.logic.Fact
|
||||
import prolog.ast.Database
|
||||
import prolog.ast.terms.Operator
|
||||
import prolog.logic.unifyLazy
|
||||
|
||||
class Assert(clause: Clause) : AssertZ(clause) {
|
||||
override val functor: Functor = "assert/1"
|
||||
|
@ -16,7 +21,7 @@ class Assert(clause: Clause) : AssertZ(clause) {
|
|||
/**
|
||||
* Assert a [Clause] as a first clause of the [Predicate] into the [Program].
|
||||
*/
|
||||
class AssertA(val clause: Clause) : Structure(Atom("asserta"), listOf(clause)) {
|
||||
class AssertA(val clause: Clause) : Operator(Atom("asserta"), null, clause) {
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
// Add clause to the program
|
||||
Program.load(listOf(clause), 0)
|
||||
|
@ -28,7 +33,7 @@ class AssertA(val clause: Clause) : Structure(Atom("asserta"), listOf(clause)) {
|
|||
/**
|
||||
* Assert a [Clause] as a last clause of the [Predicate] into the [Program].
|
||||
*/
|
||||
open class AssertZ(val clause: Clause) : Structure(Atom("assertz"), listOf(clause)) {
|
||||
open class AssertZ(val clause: Clause) : Operator(Atom("assertz"), null, clause) {
|
||||
override fun satisfy(subs: Substitutions): Answers {
|
||||
// Add clause to the program
|
||||
Program.load(listOf(clause))
|
||||
|
@ -36,3 +41,43 @@ open class AssertZ(val clause: Clause) : Structure(Atom("assertz"), listOf(claus
|
|||
return sequenceOf(Result.success(emptyMap()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When [Term] is an [Atom] or a term, it is unified with the first unifying [Clause] in the [Database].
|
||||
* The [Fact] or Clause is removed from the Database. It respects the logical update view.
|
||||
*
|
||||
* @see [SWI-Prolog Predicate retract/1](https://www.swi-prolog.org/pldoc/doc_for?object=retract/1)
|
||||
*/
|
||||
class Retract(val term: Term) : Operator(Atom("retract"), null, term) {
|
||||
override fun satisfy(subs: Substitutions): Answers = sequence {
|
||||
// Check that term is a structure or atom
|
||||
if (term !is Structure && term !is Atom) {
|
||||
yield(Result.failure(Exception("Cannot retract a non-structure or non-atom")))
|
||||
return@sequence
|
||||
}
|
||||
|
||||
val functorName = term.functor
|
||||
|
||||
Program.databases
|
||||
.filter { it.predicates.containsKey(functorName) }
|
||||
.mapNotNull { it.predicates[functorName] }
|
||||
.map { predicate ->
|
||||
val clausesIterator = predicate.clauses.iterator()
|
||||
while (clausesIterator.hasNext()) {
|
||||
val clause = clausesIterator.next()
|
||||
unifyLazy(term, clause.head, subs).forEach { unifyResult ->
|
||||
unifyResult.fold(
|
||||
onSuccess = { substitutions ->
|
||||
// If unification is successful, remove the clause
|
||||
yield(Result.success(substitutions))
|
||||
clausesIterator.remove()
|
||||
},
|
||||
onFailure = {
|
||||
// If unification fails, do nothing
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,9 @@ class Repl {
|
|||
val iterator = answers.iterator()
|
||||
|
||||
if (!iterator.hasNext()) {
|
||||
io.say("false.")
|
||||
io.say("false.\n")
|
||||
} else {
|
||||
var previous = iterator.next()
|
||||
io.say(prettyPrint(previous))
|
||||
io.say(prettyPrint(iterator.next()))
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
var command = io.prompt("")
|
||||
|
@ -57,8 +56,7 @@ class Repl {
|
|||
|
||||
when (command) {
|
||||
";" -> {
|
||||
previous = iterator.next()
|
||||
io.say(prettyPrint(previous))
|
||||
io.say(prettyPrint(iterator.next()))
|
||||
}
|
||||
"a" -> return
|
||||
"." -> return
|
||||
|
@ -88,7 +86,7 @@ class Repl {
|
|||
val subs = result.getOrNull()!!
|
||||
if (subs.isEmpty()) {
|
||||
io.checkNewLine()
|
||||
return "true.\n"
|
||||
return "true."
|
||||
}
|
||||
return subs.entries.joinToString(",\n") { "${it.key} = ${it.value}" }
|
||||
},
|
||||
|
|
Reference in a new issue