├── resources └── banner.png ├── .gitignore ├── src ├── include │ └── common.pl ├── util.pl ├── substarter.plt ├── substarter.pl ├── starter.plt └── starter.pl ├── Makefile ├── LICENSE ├── load.pl └── README.md /resources/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adkelley/prolog-starter/HEAD/resources/banner.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Backup files and other irrelevant stuff. 2 | *~ 3 | *.swp 4 | .DS_Store 5 | Icon? 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | lib/* 10 | resources/*.sketch 11 | resources/*.xcf -------------------------------------------------------------------------------- /src/include/common.pl: -------------------------------------------------------------------------------- 1 | /** Prolog starter common utility predicates 2 | 3 | Directives to be textually included by all files. 4 | 5 | @author Fixme 6 | @copyright Fixme 7 | @license Fixme 8 | @see Common Utility predicates 2 | 3 | This is an example structure for modular software development in Prolog. 4 | 5 | @author Fixme 6 | @copyright Fixme 7 | @license Fixme 8 | @see Prolog starter template substarter module 2 | 3 | This is an example structure for modular software development in Prolog. 4 | 5 | @author Fixme 6 | @copyright Fixme 7 | @license Fixme 8 | @see Prolog starter template main module 2 | 3 | This is an example structure for modular software development in Prolog. 4 | 5 | @author Fixme 6 | @copyright Fixme 7 | @license Fixme 8 | @see Interface for Prolog starter template. 2 | 3 | Acts as an interface to the system. Configures load paths and provides 4 | predicates for initiating the system. 5 | 6 | To configure for your own project, replace 'starter', with the name 7 | of your main program file. 8 | 9 | Configures internal load paths in preparation of use_module calls. 10 | Provides predicates for adding an entity to the current database 11 | 12 | @author Fixme 13 | @copyright Fixme 14 | @license Fixme 15 | */ 16 | 17 | starter_configure_globals :- 18 | set_test_options([load(always)]). 19 | 20 | 21 | % starter_configure_load_paths() is det 22 | % 23 | % Configures internal load paths in preparation of use_module calls. 24 | 25 | starter_configure_load_paths :- 26 | prolog_load_context(directory, Root), % Available during compilation 27 | starter_configure_path(Root, 'src', starter). 28 | 29 | starter_configure_path(PathPrefix, PathSuffix, Name) :- 30 | atomic_list_concat([PathPrefix,PathSuffix], '/', Path), 31 | asserta(user:file_search_path(Name, Path)). 32 | 33 | % Set everything up 34 | :- starter_configure_globals. 35 | :- starter_configure_load_paths. 36 | 37 | % documentation - uncomment to run documentation server 38 | %:- doc_server(4000). 39 | %:- portray_text(true). 40 | 41 | 42 | :- include(starter(include/common)). 43 | 44 | starter_load_project_modules :- 45 | %% TODO: Look into pldoc 46 | use_module(library(pldoc), []), % Load first to enable comment processing 47 | use_module(starter(starter), []), 48 | use_module(starter(substarter), []). 49 | 50 | starter_load_project_tests :- 51 | plunit:load_test_files([]). 52 | 53 | %% starter_test() is det. 54 | % 55 | % Loads everything and runs test suite 56 | 57 | starter_test :- 58 | starter_load_project_modules, 59 | starter_load_project_tests, 60 | starter_run_test_suite. 61 | 62 | starter_run_test_suite :- 63 | core:format('~n% Run tests ...~n'), 64 | plunit:run_tests. 65 | 66 | %% starter_cov() is det. 67 | % 68 | % Loads everything and runs the test suite with coverage analysis. 69 | 70 | starter_cov :- 71 | starter_load_project_modules, 72 | starter_load_project_tests, 73 | starter_run_test_suite_with_coverage. 74 | 75 | starter_run_test_suite_with_coverage :- 76 | core:format('~n% Run tests ...~n'), 77 | plunit:show_coverage(plunit:run_tests). 78 | 79 | %% starter_repl() is det. 80 | % 81 | % Loads everything and enters interactive mode. 82 | 83 | starter_repl :- 84 | starter_load_project_modules, 85 | starter_load_project_tests. 86 | 87 | 88 | %% starter_args() is det. 89 | % 90 | % Loads everything and executes a goal entered by the user from the command line. 91 | % Format of command line args is Module Name ExtraArgs, where Name is the 92 | % predicate you wish to run. See Makefile 93 | % 94 | starter_args :- 95 | starter_load_project_modules, 96 | core:current_prolog_flag(argv, [M,Name|ExtraArgs]), 97 | format('Goal: ~w:~w~n', [M,Name]), 98 | go(M:Name, ExtraArgs). 99 | 100 | go(_,[]). 101 | go(M:Name, [Arg|Args]) :- 102 | core:apply(M:Name, [Arg, Result]), 103 | core:format('Argument: ~w, Result: ~w~n', [Arg,Result]), 104 | go(M:Name, Args). 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![series_banner](resources/banner.png) 2 | # Template for new SWI-Prolog projects 3 | 4 | Before proceeding with the instructions below, be sure to download and install [SWI-Prolog](https://www.swi-prolog.org/Download.html). 5 | ## Instructions 6 | 7 | To convert this template to your own project: 8 | 1. Replace the word *starter* with the name of your main program in both `Makefile` and `load.pl`. 9 | 2. Replace `src/starter.pl` and `src/substarter.pl` with your own main program. 10 | 3. Replace `src/starter.plt` and `src/substarter.plt` with your own tests. 11 | 4. Use `make ` where `` is either `test`, `cov`, `repl`, or `args` to compile and run your program. 12 | 5. Uncomment lines 37-39 in `load.pl` to run a `pldoc` documentation server locally (see References) 13 | 14 | ## Makefile explanation 15 | 1. `make test` will compile the source code, and run the unit tests. 16 | 2. `make cov` performs step 1 and, in addition, will print information about coverage by file (e.g., number of clauses). 17 | 3. `make repl` will compile the source code, and will start the Prolog top level (i.e., REPL). Note that you can run a unit test(s) in the top level with [run_tests/1](https://www.swi-prolog.org/search?for=run_tests). 18 | 4. `make args ARGS="Module Goal ExtraArgs"` will compile the source code, and apply `Module:Goal` with the `ExtraArgs`. For example, `ARGS="starter string_uppercase 'hello'"` calls `starter:string_uppercase('hello', Result)`. Note that `Result` is an unbound variable supplied by `load.pl`. Its possible to supply your own unbound variables, but it requires more pattern matching than what I've coded in `load.pl`. 19 | 20 | ## License 21 | Licensed under the MIT license which can be found in the file 22 | `LICENSE` in the project root. 23 | 24 | ## References 25 | 26 | 1. [Prolog Unit Tests](https://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/plunit.html%27)) 27 | 2. [SWI-Prolog Source Documentation Infrastructure](https://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/pldoc.html%27)) 28 | 29 | ## Coding Guidelines 30 | 31 | * Use empty imports (use_module(mymodule, [])) in order to not 32 | pollute the namespace. 33 | * Always use module prefixes (mymodule:predicate(...)) in order to 34 | clarify where things are coming from. 35 | * Always use the "made-up" module prefix "core:" when calling 36 | built-in predicates. This is completely unnecessary, and doesn't even 37 | work in all cases, but I think it is a good idea as long as it doesn't 38 | cause any problems. This decision may need to be revised when 39 | compatibility between different Prologs is investigated. 40 | * Avoid the if-then-else construct. It just looks ugly. 41 | * Avoid disjunctions. They are ugly, and can be replaced by properly 42 | written helpers. Think: premises are "and", clauses are "or". 43 | * Use cuts where appropriate, and try to keep each cut on a line by 44 | itself unless its placement is obvious and consistent in each clause. 45 | PlUnit is excellent at pointing out when tests succeed but leave 46 | choice points. 47 | * Try to avoid spaces within lists and structures, but always use 48 | spaces between arguments. 49 | * Predicates, atoms, etc. should use "this_naming_style" while variables 50 | should use "ThisNamingStyle". 51 | * Try to stick to the PlDoc structure. 52 | * If in doubt, consult: [Some Coding Guidelines for Prolog](https://www.cmpe.boun.edu.tr/sites/default/files/prolog_coding_guidelines.pdf) 53 | 54 | ## Credits 55 | The structure of this starter template was modeled after a prolog project by [khueue](https://github.com/khueue/prolog-json). 56 | --------------------------------------------------------------------------------