This is a prolog runtime written in Kotlin. It utilizes Kotlins subroutines to model the search tree; as such it has a strong focus on asynchronicity.
You can start a visual prolog prompt by running the build artifact of jvm-playground
:
cd jvm-playground
mvn clean package
java -jar target/runtime-jvm-playground-*.jar
To use this interpreter in other projects, import it via Maven Central:
<dependency>
<groupId>com.github.prologdb</groupId>
<artifactId>runtime</artifactId>
<version><!-- see latest version --></version>
</dependency>
You can find the following working code in ReadmeExample.kt.
1. Declare module source:
val moduleSourceCode = """
loves(vincent, mia).
loves(marcellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).
jealous(X, Y) :-
loves(X, Z),
loves(Y, Z),
X \= Y
.
"""
// this allows the runtime to load our custom source code
val userModuleReference = ModuleReference("prog", "user")
val userModuleLoader = PredefinedSourceModuleLoader().apply {
registerModule(userModuleReference, moduleSourceCode)
}
Make sure to import all modules you need; have a look at the playground.
2. Initialize a new Runtime:
// this adds the standard library to the runtime
val moduleLoader = CascadingModuleLoader(userModuleLoader, ModuleLoader.discoverOnClasspath())
// this initializes the runtime
val runtime = DefaultPrologRuntimeEnvironment(moduleLoader)
val loadedUserModule = runtime.assureModuleLoaded(userModuleReference)
You can load module source code from the classpath with ClasspathPrologSourceModuleLoader
,
and Kotlin-only modules with PredefinedModuleLoader
. For a combination, look at [how the
standard library does it
3. Run a query
val queryCode = """jealous(marcellus, Person)."""
val queryLexer = Lexer(
SourceUnit("query"),
LineEndingNormalizer(CharacterIterable(queryCode).iterator())
)
val queryParseResult = PrologParser().parseQuery(queryLexer, loadedUserModule.localOperators)
if (queryParseResult.reportings.isNotEmpty()) {
// parsing not successful
}
val queryAST = queryParseResult.item!!
Once you have the query AST, you can run it:
val solutions: LazySequence<Unification> = runtime.fulfill(userModuleReference.moduleName, queryAST)
val personsJealousOfMarcellus = solutions
.mapRemaining { it[Variable("Person")] }
.mapRemaining { (it as Atom).name }
.remainingTo(::mutableSetOf)
- async: async and coroutine primitives that are suitable for the prolog proof search
semantics (
kotlin.sequences.Sequence
is not!). Has no ties to actual prolog. - core
- defines the structure of the core elements: terms, modules, queries
- all semantics necessary to interpret ASTs (unification, proof search)
- parser: parses prolog source into an AST as defined in the core module
- stdlib:
- builtin predicates (e.g.
=/2
,append/3
, ...) - operators
- maths (
is/2
), - ...
- builtin predicates (e.g.
- jvm-playground: a simple visual prompt. Used mainly for testing during development.
- tests: end-to-end tests for all builtin functionality