Prolog.NET.Model 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Prolog.NET.Model --version 0.1.0
                    
NuGet\Install-Package Prolog.NET.Model -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Prolog.NET.Model" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Prolog.NET.Model" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Prolog.NET.Model" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Prolog.NET.Model --version 0.1.0
                    
#r "nuget: Prolog.NET.Model, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Prolog.NET.Model@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Prolog.NET.Model&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Prolog.NET.Model&version=0.1.0
                    
Install as a Cake Tool

Prolog.NET.Model

Schema-first DSL for constructing typed Prolog databases in C#. Declare functor and relation shapes using attributes on partial records; the companion source generator emits strongly-typed factory methods at compile time; PrologSerializer converts the result to .pl source.

Generator

Prolog.NET.Model is designed to be used with Prolog.NET.Model.Generator, a Roslyn incremental analyzer that must be referenced alongside this package:

<ProjectReference Include="..\Prolog.NET.Model.Generator\Prolog.NET.Model.Generator.csproj"
                  OutputItemType="Analyzer"
                  ReferenceOutputAssembly="false" />

If a decorated type is not declared partial, the generator emits diagnostic PNET001 (error). Set <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> in your .csproj to inspect generated files under obj/<Configuration>/<TFM>/generated/.

Usage

Declaring Relations

A relation type is a partial record decorated with PrologRelationName and one or more PrologRelation<T…> attributes. Place it inside a static partial class to group related declarations:

public static partial class PersonModule
{
    [PrologModule("person")]
    [PrologRelationName("person")]
    [PrologRelation<Name>]
    public partial record Person : IRelation;
}
  • [PrologModule("person")] — assigns the type to a Prolog module; generated Query() calls include the module:functor(…) qualifier automatically.
  • [PrologRelationName("person")] — sets the Prolog functor name.
  • [PrologRelation<T…>] — one attribute per arity; the number of type parameters determines how many arguments Fact(…) and Query(…) accept.

Use PrologArgument as the wildcard type for each position (a marker type; never instantiated). Multiple PrologRelation attributes on the same type register multiple arities.

Declaring Functors

A functor type is a partial record decorated with PrologFunctor<T…>:

[PrologFunctor<PrologArgument, PrologArgument>("name")]
public partial record Name : IFunctor;

The generator emits Name.Of(PrologTerm, PrologTerm) returning a PrologCompound. For example:

Name.Of(PrologDSL.Atom.Create("alice"), PrologDSL.Atom.Create("smith"))
// → PrologCompound("name", […])  →  name(alice, smith)

A type can carry both relation and functor attributes simultaneously, letting it act as both a top-level relation and a reusable compound term:

[PrologModule("addresses")]
[PrologRelationName("address")]
[PrologRelation<PrologArgument, PrologArgument, PrologArgument>]
[PrologFunctor<PrologArgument, PrologArgument, PrologArgument>("address")]
public partial record Address : IRelation, IFunctor;

Generated Methods Summary

Attribute Generated method Returns
PrologRelationAttribute<T…> Fact(…) PrologFact
PrologRelationAttribute<T…> Query(…) BodyGoal
PrologRelationNameAttribute Rule() RuleBuilder
PrologRelationNameAttribute Multifile() PrologDatabaseItem
PrologFunctorAttribute<T…> Of(…) PrologCompound

Three-Module Example

Declarations for three related modules:

public static partial class PersonModule
{
    // 'name' compound: used inside person facts as name(first, last)
    [PrologFunctor<PrologArgument, PrologArgument>("name")]
    public partial record Name : IFunctor;

    [PrologModule("person")]
    [PrologRelationName("person")]
    [PrologRelation<Name>]
    public partial record Person : IRelation;
}

public static partial class AddressesModule
{
    // 'address' is both a top-level relation and a reusable compound term
    [PrologModule("addresses")]
    [PrologRelationName("address")]
    [PrologRelation<PrologArgument, PrologArgument, PrologArgument>]    // address(street, number, city)
    [PrologFunctor<PrologArgument, PrologArgument, PrologArgument>("address")]
    public partial record Address : IRelation, IFunctor;
}

public static partial class ResidentsModule
{
    [PrologModule("residents")]
    [PrologRelationName("resident")]
    [PrologRelation<Name, Address>]
    public partial record Resident : IRelation;

    [PrologModule("residents")]
    [PrologRelationName("live_together")]
    [PrologRelation<Name, Name>]
    public partial record LiveTogether : IRelation;
}

Building the databases:

var alice       = PrologDSL.Atom.Create("alice");
var smith       = PrologDSL.Atom.Create("smith");
var bob         = PrologDSL.Atom.Create("bob");
var jones       = PrologDSL.Atom.Create("jones");
var elm         = PrologDSL.Atom.Create("elm");
var springfield = PrologDSL.Atom.Create("springfield");
var n42         = PrologDSL.Atom.CreateInt(42);

PrologModule person = PrologDSL.Module.Create("person", [
    PersonModule.Person.Fact(PersonModule.Name.Of(alice, smith)),   // person(name(alice, smith)).
    PersonModule.Person.Fact(PersonModule.Name.Of(bob, jones)),     // person(name(bob, jones)).
]);

PrologModule addresses = PrologDSL.Module.Create("addresses", [
    AddressesModule.Address.Fact(elm, n42, springfield),            // address(elm, 42, springfield).
]);

PrologModule residents = PrologDSL.Module.Create("residents", [
    // resident(name(alice, smith), address(elm, 42, springfield)).
    ResidentsModule.Resident.Fact(
        PersonModule.Name.Of(alice, smith),
        AddressesModule.Address.Of(elm, n42, springfield)),
    // resident(name(bob, jones), address(elm, 42, springfield)).
    ResidentsModule.Resident.Fact(
        PersonModule.Name.Of(bob, jones),
        AddressesModule.Address.Of(elm, n42, springfield)),
    // live_together(P1, P2) :-
    //     person:person(P1), person:person(P2),
    //     resident(P1, A), resident(P2, A).
    ResidentsModule.LiveTogether.Rule()
        .AddDefinition(rule => rule
            .Variables("P1", "P2", "A", (p1, p2, a, r) => r
                .Arguments(p1, p2)
                .Body(PersonModule.Person.Query(p1)              // person:person(P1)
                    .And(PersonModule.Person.Query(p2))          // person:person(P2)
                    .And(ResidentsModule.Resident.Query(p1, a))  // resident(P1, A)
                    .And(ResidentsModule.Resident.Query(p2, a))))),
]);

Serializing

string personSource    = PrologSerializer.Serialize(person);
string addressSource   = PrologSerializer.Serialize(addresses);
string residentsSource = PrologSerializer.Serialize(residents);

use_module directives are emitted automatically for any cross-module calls detected in rule bodies. For example, residentsSource produces:

:- module(residents, [resident/2, live_together/2]).

:- use_module(person).

resident(name(alice, smith), address(elm, 42, springfield)).
resident(name(bob, jones), address(elm, 42, springfield)).
live_together(P1, P2) :-
    person:person(P1),
    person:person(P2),
    resident(P1, A),
    resident(P2, A).

Tests

End-to-end serialization tests for this package live in tests/Prolog.NET.Model.Tests/. The ReadmeTests class builds the three-module example from this README and asserts the exact serialized output for each module.


Appendix: Type Reference

DSL Entry Point

Type Description
PrologDSL Static entry point; PrologDSL.Atom.Create, PrologDSL.Atom.CreateInt, PrologDSL.Database.Create, PrologDSL.Module.Create

Database Types

Type Description
PrologDatabase Ordered list of PrologDatabaseEntry records
PrologModule Named wrapper around a PrologDatabase; serializes with a module declaration and auto-emitted use_module directives

Term Types

Type Description
PrologAtom A named atom
PrologIntAtom An integer atom (long)
PrologVariable A Prolog variable
PrologCompound A compound term with a functor and arguments

Body Goal Types

Type Description
Call A goal call, optionally qualified with a module
Conjunction Left , Right
Disjunction Left ; Right
True The true goal

Goals support .And() and .Or() builder methods.

Attributes

Attribute Description
PrologModuleAttribute(string) Assigns the type to a Prolog module; qualifies generated Query() calls
PrologRelationNameAttribute(string) Names the relation and marks the type for the relation pipeline
PrologRelationAttribute<T1..T4> Declares an arity-N overload for Fact / Query / Rule() / Multifile()
PrologFunctorAttribute<T1..T4> Declares an arity-N Of(…) factory method returning PrologCompound

Development Notes

This package was developed with the assistance of AI coding tools (Claude Code), under the supervision of the author. All design decisions, architecture choices, and code reviews were made by the author.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 115 3/27/2026
0.1.0 117 3/10/2026