{"id":13560678,"url":"https://github.com/trealla-prolog/trealla","last_synced_at":"2026-06-05T07:01:03.321Z","repository":{"id":54516904,"uuid":"522424587","full_name":"trealla-prolog/trealla","owner":"trealla-prolog","description":"A compact, efficient Prolog interpreter written in plain old C.","archived":false,"fork":false,"pushed_at":"2026-05-31T00:48:53.000Z","size":6132,"stargazers_count":360,"open_issues_count":20,"forks_count":30,"subscribers_count":15,"default_branch":"main","last_synced_at":"2026-05-31T02:28:58.443Z","etag":null,"topics":["c","iso-prolog-standard","prolog","prolog-implementation","prolog-interpreter","prolog-programming-language"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trealla-prolog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-08-08T06:03:02.000Z","updated_at":"2026-05-31T00:48:46.000Z","dependencies_parsed_at":"2023-10-03T03:49:41.585Z","dependency_job_id":"63ce3ccb-b4fa-496c-b30f-87e76e0abf45","html_url":"https://github.com/trealla-prolog/trealla","commit_stats":null,"previous_names":[],"tags_count":2341,"template":false,"template_full_name":null,"purl":"pkg:github/trealla-prolog/trealla","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trealla-prolog%2Ftrealla","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trealla-prolog%2Ftrealla/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trealla-prolog%2Ftrealla/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trealla-prolog%2Ftrealla/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trealla-prolog","download_url":"https://codeload.github.com/trealla-prolog/trealla/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trealla-prolog%2Ftrealla/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33932048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","iso-prolog-standard","prolog","prolog-implementation","prolog-interpreter","prolog-programming-language"],"created_at":"2024-08-01T13:00:48.593Z","updated_at":"2026-06-05T07:01:03.314Z","avatar_url":"https://github.com/trealla-prolog.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"Trealla Prolog\n==============\n\nA compact, efficient ISO Prolog interpreter. Written in plain old C\nand using a plain old Makefile.\n\n\tMIT licensed\n\tIntegers \u0026 Rationals are unbounded\n\tAtoms are UTF-8 of unlimited length\n\tThe default double-quoted representation is *chars* list\n\tStrings \u0026 slices are super-efficient (especially with mmap'd files)\n\tREPL with history\n\tRuns on Linux, Android, BSD, macOS, and WebAssembly (WASI) \u0026 Go\n\tWindows build is of indeterminate state and is unsupported\n\tAPI for calling from C (or by using WASM from Go \u0026 JS)\n\tForeign function interface (FFI) for calling out to user code\n\tAccess SQLITE databases using builtin module (uses FFI)\n\tConcurrency via tasks / linda / futures / engines (generators)\n\tPre-emptive multi-threading\n\tAttributed variables: freeze/2 dif/2, when/2\n\tConstraint libraries: CLP(B), CLP(Z)\n\tBlackboarding primitives: bb_put, bb_b_put/2, bb_get/2\n\tSockets library\n\t...\n\tFFIs for GNU Scientific Library (GSL), SQLite, Raylib ##EXPERIMENTAL##\n\tDelimited continuations ##EXPERIMENTAL##\n\tRational trees ##EXPERIMENTAL##\n\n\nAvailable from: [https://github.com/trealla-prolog/trealla](https://github.com/trealla-prolog/trealla).\n\nRuns with [Jupyter Notebooks](https://github.com/LogtalkDotOrg/logtalk-jupyter-kernel#readme).\n\n\nLogo\n====\n\n![Trealla Logo: Trealla](trealla.png)\n\n\nUsage\n=====\n\n\ttpl [options] [files] [-- args]\n\nwhere options can be:\n\n\t-O0, --noopt       - no optimization\n\t-f                 - *.tplrc* not loaded\n\t-l file            - load file\n\tfile               - load file\n\t-g goal            - query goal (only used once)\n\t--library path     - alt to TPL_LIBRARY_PATH env var\n\t-t, --trace        - trace\n\t-q, --quiet        - quiet mode (no banner)\n\t-v, --version      - version\n\t-h, --help         - help\n\t-d, --daemonize    - daemonize\n\t-w, --watchdog     - create watchdog\n\t--autofail         - autofail queries at the toplevel\n\t--consult          - consult from STDIN\n\t--nolimit          - no memory limit\n\nFor example:\n\n\ttpl -g test2,halt samples/sieve\n\nInvocation without any goal presents the REPL.\n\nThe default path to the library is relative to the executable location.\n\nThe file *~/.tplrc* is consulted on startup unless the *-f* option is present.\n\nWhen consulting, reconsulting and deconsulting files the *.pl* version\nof the filename is always preferred (if not specified) when looking for a\nfile.\n\n\nA note on UTF-8\n===============\n\nTrealla uses UTF-8 internally and this works well with modern operating\nsystems that are already [[1](https://www.utf8everywhere.org/)], or moving to\n[[2](https://en.wikipedia.org/wiki/Unicode_in_Microsoft_Windows#UTF-8)],\nnative UTF-8.\n\nIt aligns well with standard C as functions like strcmp/memcmp that\nrequire no special handling to respect codepoint order. This also works\nseamlessly with the implementation of double-quoted *strings* (ie.\nchars-list), DCGs, and mmap'd files. Any code-point specific\nrequirements, like *get_char*, *get_code*, *sub_atom*, *atom_length*,\n*atom_codes*, *atom_chars* \u0026 *_upper/*_lower are handled on the fly.\n\nUTF-8 atoms do not need to be quoted unless they contain breaking\ncharacters...\n\n```console\n\t?- [user].\n\t是.            % be: means, approximately, \"True\".\n\t不是 :- \\+ 是.  % not be: means, approximately, \"False\".\n\t\u003cCTRL-D\u003e\n\t   true.\n\t?- 是.\n\t   true.\n\t?- 不是.\n\t   false.\n\t```\n\n\t```console\n\t?- X = 国字.\n\t   X = 国字.\n\t?-\n```\n\nTrealla accepts as a var any atom beginning with an uppercase\ncharacter...\n\n```console\n\t?- atom_upper(δ,C).\n\t   C = Δ.\n\t?- Δ is 123456-123455.\n\t   Δ = 1.\n\t?-\n```\n\n\nBuilding\n========\n\nWritten in plain-old C99.\n\n\tgit clone https://github.com/trealla-prolog/trealla.git\n\tcd trealla\n\nOn Debian-like systems, you will need to install (if not alread( the following\npackages to set up a build environment:\n\n\tsudo apt install build-essential git libedit-dev libffi-dev libssl-dev\n\nThen...\n\n\tmake\n\nTo build without FFI:\n\n\tmake NOFFI=1\n\nTo build without SSL:\n\n\tmake NOSSL=1\n\nTo build without pre-emptive multi-threading support:\n\n\tmake NOTHREADS=1\n\nTo build (as a last resort) with the included ISOCLINE sources (default is to use EDITLINE,\nexcept with WASI \u0026 Windows):\n\n\tmake ISOCLINE=1\n\nOlder compilers may require:\n\n\tmake NOPEDANTIC=1\n\nto avoid issues with newer flags.\n\nFinally...\n\n\tmake install\n\nto install locally.\n\nOptionally...\n\n\tmake test\n\nand there should be no errors.\n\nFurther to test with `valgrind` (on Linux):\n\n\tmake clean \u0026\u0026 make debug \u0026\u0026 make valgrind\n\nor  more thoroughly (on MacOS):\n\n\tmake clean \u0026\u0026 make sanitize \u0026\u0026 make test\n\nShould ideally show no memory out-of-bounds, null-pointer, use after\nfree or memory leaks (there may a few spurious errors).\n\n\nOn macOS:\n\n\tbrew install libffi openssl coreutils\n\nBy default `editline` is used on `'nix` systems, however if using GNU\nreadline instead (make READLINE=1) install the BREW version of readline.\n\n\nBuilding with MUSL\n==================\n\nOn Ubuntu:\n\n\tsudo apt install musl-tools\n\tmake CC=musl-gcc OPT=-static NOFFI=1 NOSSL=1 ISOCLINE=1\n\n\nWebAssembly (WASI)\n==================\n\nTrealla has support for WebAssembly System Interface (WASI).\n\nFor an easy build envrionment, set up\n[wasi-sdk](https://github.com/WebAssembly/wasi-sdk).\n[Binaryen](https://github.com/WebAssembly/binaryen) is needed for optimization.\n\nTo build the WebAssembinary binary, set CC to wasi-sdk's clang:\n\n\tmake CC=/opt/wasi-sdk/bin/clang wasm\n\nSetting WASI_CC also works as an alternative to CC.\n\n\nCross-compile for Windows x64\n=============================\n\nTo cross-compile on Linux and produce a Windows/x86-64 executable...\n\n\tsudo apt install mingw-w64\n\tmake WIN=1 NOFFI=1 NOSSL=1\n\n```console\n\t$ file tpl.exe\n\ttpl.exe: PE32+ executable (console) x86-64, for MS Windows\n```\n\nSome have reported success with a native Windows build using msys2.\n\n\nCross-compile for Linux x86\n===========================\n\nTo cross-compile on Linux and produce a Linux/x86-32 executable...\n\n\tsudo apt install gcc-multilib\n\tsudo apt install libssl-dev:i386 libffi-dev:i386 libreadline-dev:i386\n\tmake OPT=-m32\n\n```console\n\t$ file tpl\n\ttpl: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=31f643d7a4cfacb0a34e81b7c12c78410493de60, for GNU/Linux 3.2.0, with debug_info, not stripped\n```\n\n\nContributions\n=============\n\nContributions are welcome.\n\n\nAcknowledgements\n================\n\nThis project (in current incarnation) started in March 2020 and it\nwould not be where it is today without help from these people:\n\n\t- [Xin Wang](https://github.com/dram)\n\t- [Paulo Moura](https://github.com/pmoura)\n\t- [Markus Triska](https://github.com/triska)\n\t- [Jos De Roo](https://github.com/josd)\n\t- [Ulrich Neumerkel](https://github.com/uwn)\n\t- [Guregu](https://github.com/guregu)\n\n\nUnbounded integers (Bigints) and Rationals\n==========================================\n\nFor unbounded arithmetic Trealla uses a modified fork of the\n[imath](https://github.com/infradig/imath)\nlibrary, which is partially included in the source. Note, unbounded\nintegers (aka. bigints) are for arithmetic purposes only and will give a\ntype_error when used in places not expected. The *imath* library has a bug\nwhereby printing large numbers becomes exponentially slower (100K+ digits).\n\n\nStrings\n=======\n\nDouble-quoted strings, when *set_prolog_flag(double_quotes,chars)* is set\n(which is the default) are stored as packed UTF-8 byte arrays. This is\ncompact and efficient. Such strings emulate a list representation and\nfrom the programmer point of view are very much indistinguishable from\nlists.\n\nA good use of such strings is *open(filename,read,Str,[mmap(Ls))*\nwhich gives a memory-mapped view of a file as a string *Ls*. List\noperations on files are now essentially zero-overhead! DCG applications\nwill gain greatly (*phrase_from_file/[2-3]* uses this).\n\nBoth strings and atoms make use of low-overhead reflist-counted byte slices\nwhere appropriate.\n\n\nNon-standard predicates\n=======================\n\n\thelp/0\n\thelp/1\t\t\t\t\t\t# help(+functor) or help(+PI)\n\thelp/2\t\t\t\t\t\t# help(+PI,+atom) where *atom* can be *swi* or *tau*\n\n\tmodule_help/1\t\t\t\t# help(+module)\n\tmodule_help/2\t\t\t\t# help(+module,+functor) or help(+module,+PI)\n\tmodule_help/3\t\t\t\t# help(+module,+PI,+atom) where *atom* can bw *swi* or *tau*\n\n\tsource_info/2\t\t\t\t# source_info(+PI, -list)\n\tmodule_info/2\t\t\t\t# module_info(+atom, -list)\n\n\tmodule/1\t\t\t\t\t# module(?atom)\n\tmodules/1\t\t\t\t\t# modules(-list)\n\n\tload_text/2\t\t\t\t\t# load_text(+atom,+opts)\n\n\tlisting/0\n\tlisting/1\t\t\t\t\t# listing(+PI)\n\n\tabolish/2\t\t\t\t\t# abolish(+pi,+list)\n\tpretty/1\t\t\t\t\t# pretty-print version of listing/1\n\tbetween/3\n\tmsort/2\t\t\t\t\t\t# version of sort/3 with duplicates\n\tsamsort/2                   # same as msort/2\n\tmerge/3\n\tformat/[1-3]\n\tportray_clause/[1-2]\n\tpredicate_property/2\n\tevaluable_property/2\n\tnumbervars/[1,3-4]\n\te/0\n\tname/2\n\ttab/[1,2]\n\n\tget_unbuffered_code/1\t\t# read a single unbuffered code\n\tget_unbuffered_char/1\t\t# read a single unbuffered character\n\n\tread_from_atom/2            # read_from_atom(+atom,?term)\n\tread_from_chars/2\t        # read_from_chars(+chars,?term)\n\tread_term_from_atom/3       # read_term_from_atom(+atom,?term,+optlist)\n\tread_term_from_chars/3\t    # read_term_from_chars(+chars,?term,+optlist)\n\n\tread_from_chars_/3\t        # read_from_chars+(?term,+chars,-rest)\n\tread_term_from_chars_/4\t    # read_term_from_chars+(?term,+optlist,+chars,-rest)\n\n\twrite_term_to_atom/3        # write_term_to_atom(?atom,?term,+oplist)\n\twrite_canonical_to_atom/3   # write_canonical_to_atom(?atom,?term,+oplist)\n\tterm_to_atom/2              # term_to_atom(?atom,?term)\n\n\tsetrand/1                   # set_seed(+integer) set random number seed\n\tsrandom/1                   # set_seed(+integer) set random number seed\n\tset_seed/1                  # set_seed(+integer) set random number seed\n\tget_seed/1                  # get_seed(-integer) get random number seed\n\trand/1                      # rand(-integer) integer [0,RAND_MAX]\n\trandom/1                    # random(-float) float [0.0,\u003c1.0]\n\trandom_between/3            # random_between(+int,+int,-int) integer [arg1,\u003carg2]\n\n\trandom_float/0              # function returning float [0.0,\u003c1.0]\n\trandom_integer/0            # function returning integer [0,RAND_MAX]\n\trand/0                      # function returning integer [0,RAND_MAX]\n\n\tgensym/2\t\t\t\t\t# gensym(+atom,-atom)\n\treset_gensym/1\t\t\t\t# reset_gensym(+atom)\n\n\tcall_residue_vars/2\t\t\t# call_residue_vars(+goal,-list)\n\texpand_term/2               # expand_term(+rule,-term)\n\tsub_string/5\t\t\t\t# sub_string(+string,?before,?len,?after,?substring)\n\tatomic_concat/3             # atomic_concat(+atom,+list,-list)\n\tatomic_list_concat/2\t    # atomic_list_concat(L,Atom)\n\tatomic_list_concat/3\t    # atomic_list_concat(L,Sep,Atom)\n\twrite_term_to_chars/3\t    # write_term_to_chars(?chars,?term,+list)\n\twrite_canonical_to_chars/3  # write_canonical_to_chars(?chars,?term,+list)\n\tchars_base64/3              # currently options are ignored\n\tchars_urlenc/3              # currently options are ignored\n\thex_chars/2                 # as number_chars, but in hex\n\toctal_chars/2               # as number_chars, but in octal\n\tpartial_string/2            # partial_string(+string,-String)\n\tpartial_string/3            # partial_string(+string,-String,-Var)\n\tif/3, (*-\u003e)/2               # soft-cut\n\tcall_det/2\t\t\t\t\t# call_det(+call,?boolean)\n\tcopy_term_nat/2             # doesn't copy attrs (same as copy_term/2)\n\tunifiable/3                 # unifiable(+term1,+term2,-Goals)\n\t?=/2                        # ?=(+term1,+term2)\n\tterm_expansion/2\n\tgoal_expansion/2\n\tcyclic_term/1\n\tterm_singletons/2\n\tfindall/4\n\tsort/4\n\tignore/1\n\tis_list/1\n\tis_partial_list/1\n\tis_list_or_partial_list/1\n\tis_stream/1\n\tterm_hash/2\n\tterm_hash/3\t\t\t\t\t# ignores arg2 (options)\n\ttime/1\n\tinf/0\n\tnan/0\n\t\\uXXXX and \\UXXXXXXXX \t\t# Unicode escapes (for JSON)\n\tgcd/2\n\tuuid/1                      # uuid(-string)\n\tload_files/[1,2]\n\tmodule/1\n\tline_count/2\n\tatom_number/2\t\t\t\t# *SWI-Prolog* compatible\n\tcfor/3\t\t\t\t\t\t# cfor(+evaluable,+evaluable,-var)\n\trepeat/1\t\t\t\t\t# repeat(+integer)\n\tmake/0\n\targv/1\t\t\t\t\t\t# argv(-list)\n\traw_argv/1\t\t\t\t\t# raw_argv(-list)\n\n\trdiv/2\t\t\t\t\t\t# evaluable\n\tnumerator/1\t\t\t\t\t# evaluable\n\tdenominator/1\t\t\t\t# evaluable\n\trational/1\n\n\twith_output_to(chars(Cs), Goal)\t\t# *SWI-Prolog* compatible\n\twith_output_to(string(Cs), Goal)\t# *SWI-Prolog* compatible\n\twith_output_to(atom(Atom), Goal)\t# *SWI-Prolog* compatible\n\n\tdivmod/4                    # *SWI-Prolog* compatible\n\tread_line_to_codes/2\t   \t# *SWI-Prolog* compatible\n\tread_line_to_codes/3\t   \t# *SWI-Prolog* compatible\n\tread_line_to_string/2\t\t# *SWI-Prolog* compatible\n\tread_file_to_string/3\t\t# *SWI-Prolog* compatible\n\tsplit_string/4\t\t\t\t# *SWI-Prolog* compatible\n\toption/2-3\t\t\t\t\t# *SWI-Prolog* compatible (see library(option))\n\tfindnsols/4\t\t\t\t\t# *SWI-Prolog* compatible\n\tnb_setarg/3\t\t\t\t\t# *SWI-Prolog* compatible (only with small integer values)\n\twriteln/1\t\t\t\t\t# *SWI-Prolog* compatible\n\twriteln/2\t\t\t\t\t# *SWI-Prolog* compatible\n\tcall_nth/2\t\t\t\t\t# *SWI-Prolog* compatible\n\toffset/2\t\t\t\t\t# *SWI-Prolog* compatible\n\tlimit/2\t\t\t\t\t\t# *SWI-Prolog* compatible\n\tcall_with_time_limit/2\t\t# *SWI-Prolog* compatible\n\ttime_out/3\t\t\t\t\t# *SICStus Prolog* compatible\n\n\tgetenv/2\n\tsetenv/2\n\tunsetenv/1\n\n\tdirectory_files/2\n\tdelete_file/1\n\texists_file/1\n\trename_file/2\n\tcopy_file/2\n\ttime_file/2\n\tsize_file/2\n\texists_directory/1\n\tmake_directory/1\n\tmake_directory_path/1\n\tworking_directory/2\n\tchdir/1\n\tabsolute_file_name/[2,3]\t# expand(Bool) \u0026 relative_to(file) options\n\tis_absolute_file_name/1\n\taccess_file/2\n\tset_stream/2\t\t\t\t# only supports alias/1 \u0026 type/1 property\n\talias/2\t\t\t\t\t\t# alias(?integer,+atom)\n\n\tstring_upper/2\n\tstring_lower/2\n\tatom_upper/2\n\tatom_lower/2\n\n\tpopcount/1                  # function returning number of 1 bits\n\tlsb/1                       # function returning the least significant bit of a positive integer (count from zero)\n\tmsb/1                       # function returning the most significant bit of a positive integer (count from zero)\n\tlog10/1                     # function returning log10 of arg\n\tnow/0                       # function returning Unix epoch in whole secs\n\tnow/1                       # now(-integer) Unix epoch in whole secs\n\tget_time/1                  # get_time(-float) Unix epoch in secs\n\twall_time/1                 # wall_time(-float) elapsed clock time in secs\n\tcpu_time/1                  # cpu_time(-float) elapsed CPU time in secs\n\n\tposix_strftime/3\t\t\t# posix_strftime(+format,-string,+tm(NNN,...))\n\tposix_strptime/3\t\t\t# posix_strptime(+format,+string,-tm(NNN,...))\n\tposix_mktime/2\t\t\t\t# posix_mktime(+tm(NNN,...),-seconds)\n\tposix_gmtime/2\t\t\t\t# posix_gmtime(+seconds,-tm(NNN,...))\n\tposix_localtime/2\t\t\t# posix_localtime(+seconds,-tm(NNN,...))\n\tposix_ctime/2\t\t\t\t# posix_time(+seconds,-atom)\n\tposix_time/1\t\t\t\t# posix_time(-seconds)\n\tposix_getpid/1\t\t\t\t# posix_pid(-pid)\n\tposix_getppid/1\t\t\t\t# posix_ppid(-pid)\n\tposix_fork/1\t\t\t\t# posix_fork(-pid)\n\n\n\tcurrent_key/1\n\tstring_concat/3\t\t\t\t# string_concat(+string,+string,?string)\n\tstring_length/2\n\tsleep/1                     # sleep time in secs\n\tsplit/4                     # split(+string,+sep,?left,?right)\n\tshell/1\n\tshell/2\n\tdate_time/6\n\tdate_time/7\n\tloadfile/2                  # loadfile(+filename,-string)\n\tsavefile/2                  # savefile(+filename,+string)\n\tgetfile/2                   # getfile(+filename,-strings)\n\tgetfile/3                   # getfile(+filename,-strings,+opts)\n\tgetline/1                   # getline(-string)\n\tgetline/2                   # getline(+stream,-string)\n\tgetline/3                   # getline(+stream,-string,+opts)\n\tgetlines/1                  # getlines(-strings)\n\tgetlines/2                  # getlines(+stream,-strings)\n\tgetlines/3                  # getlines(+stream,-strings,+opts)\n\n\topen(stream(Str),...)       # with open/4 reopen a stream\n\topen(F,M,S,[mmap(Ls)])      # with open/4 mmap() the file to Ls\n\n\treset/3\t\t\t\t\t\t# parser_reset(:goal,?ball,-cont)\n\tshift/1\t\t\t\t\t\t# shift(+ball)\n\n\tterm_variables/3\n\treplace/4                   # replace(+string,+old,+new,-string)\n\nWhere `getlines/3` supports `terminator(+Bool)` to keep the line\nterminator or not (default). Also `empty(+Bool)` to end with the first\nempty line or not (default), this can be useful for loading a list\nof headers in an HTTP response.\n\nNote: consult/1 and load_files/2 support lists of files as args. Also\nsupport loading into modules eg. *consult(MOD:FILE-SPEC)*.\n\nUse these *POSIX* system calls for interprocess creation and\ncommunication...\n\n\tpopen/3                     # popen(+cmd,+mode,-stream)\n\tpopen/4                     # popen(+cmd,+mode,-stream,+opts)\n\nFor example...\n\n```console\ntpl -g \"popen('ps -a',read,S,[]),getlines(S,Ls),close(S),maplist(println,Ls),halt\"\n\tPID   TTY      TIME     CMD\n\t2806  tty2     00:00:00 gnome-session-b\n\t31645 pts/0    00:00:00 tpl\n\t31646 pts/0    00:00:00 sh\n\t31647 pts/0    00:00:00 ps\n```\n\nFor general *POSIX* process creation use these *SWI-Prolog* compatible calls...\n\n\tprocess_create/3\t\t\t# process_create(+cmd,+args,+opts)\n\tprocess_wait/2\t\t\t\t# process_wait(+pid,+opts)\n\tprocess_wait/1\t\t\t\t# process_wait(+pid)\n\tprocess_kill/2\t\t\t\t# process_kill(+pid,+sigint)\n\tprocess_kill/1\t\t\t\t# process_kill(+pid)\n\nFor example...\n\n```console\n\t?- process_create('ls',['-l'],[process(Pid)]),process_wait(Pid).\n\ttotal 2552\n\t   4 -rw-rw-r-- 1 andrew andrew    1813 Aug 25 10:18 ATTRIBUTION\n\t   4 -rw-rw-r-- 1 andrew andrew    1093 Aug 25 10:18 LICENSE\n\t   8 -rw-rw-r-- 1 andrew andrew    7259 Sep 18 18:27 Makefile\n\t  24 -rw-rw-r-- 1 andrew andrew   23709 Sep 19 08:56 README.md\n\t   4 -rw-rw-r-- 1 andrew andrew      28 Aug 25 10:18 _config.yml\n\t   4 drwxrwxr-x 2 andrew andrew    4096 Sep 17 10:41 docs\n\t   4 drwxrwxr-x 2 andrew andrew    4096 Sep 18 21:29 library\n\t   4 drwxrwxr-x 2 andrew andrew    4096 Sep  3 13:02 samples\n\t   4 drwxrwxr-x 6 andrew andrew    4096 Sep 19 09:38 src\n\t   4 drwxrwxr-x 5 andrew andrew    4096 Sep 14 20:49 tests\n\t1448 -rwxrwxr-x 1 andrew andrew 1478712 Sep 19 09:38 tpl\n\t   8 -rw-rw-r-- 1 andrew andrew    7671 Aug 25 10:18 tpl.c\n\t  16 -rw-rw-r-- 1 andrew andrew   13928 Sep 18 18:28 tpl.o\n\t  36 -rw-rw-r-- 1 andrew andrew   33862 Aug 25 10:18 trealla.png\n\t   Pid = 735602.\n\t?-\n```\n\nNote: read_term/[2,3] supports the positions(Start,End) and the\nline_counts(Start,End) property options to report file information.\nThis is analogous to stream_property/2 use of position(Pos) and\nline_count(Line) options.\n\nNote: read_term, write_term \u0026 friends support the *json(Boolean)*\noption to make more sympathetic support for JSON using the builtin\nparsing and printing mechanisms.\n\n\nDefinite Clause Grammars\n========================\n\nUses Ulrich Neumerkel's standard reference library.\n\n\t:- use_module(library(dcgs)).\n\n\nBlackboard functions\n====================\n\nThe blackboard is module specific and shared among threads. The\nfollowing are *SICStus Prolog* \u0026 *SWI-Prolog* (if `expects_dialect(sicstus)`)\ncompatible:\n\n\tbb_put/2\t\t\t\t\t# bb_put(:atom, +term)\n\tbb_get/2\t\t\t\t\t# bb_get(:atom, ?term)\n\tbb_update/3\t\t\t\t\t# bb_update(:atom, ?term, ?term)\n\tbb_delete/2\t\t\t\t\t# bb_delete(:atom, ?term)\n\nThe following is undone on backtracking and is a *Scryer Prolog*\nextension:\n\n\tbb_b_put/2\t\t\t\t\t# bb_b_put(:atom, +term)\n\n\nCrypto functions\n================\n\nHash a plain-text data string to a hexadecimal byte string\nrepresenting the cryptographic strength hashed value. The options\nare *algorithm(Name)* where *Name* can be *sha256*, *sha384* or\n*sha512*, and optionally *hmac(Key)* where *Key* is a list of byte\nvalues. This predicate is only available when compiled with OpenSSL...\n\n\tcrypto_data_hash/3          # crypto_data_hash(+data,-hash,+options)\n\nGenerate 'N' random bytes.\n\n\tcrypto_n_random_bytes(N, Bs) # crypto_n_random_bytes(+integer, -codes)\n\nConvert a hexadecimal string to a byte-list. At least one arg must be\ninstantiated...\n\n\thex_bytes/2                 # hex_bytes(?hash,?bytes)\n\n\nParsing CSV with builtins\n=========================\n\nFast, efficient parsing of CSV files.\n\nReading:\n\n\tparse_csv_line/2\t\t\t# parse_csv_line(+atom,-list)\n\tparse_csv_line/3\t\t\t# parse_csv_line(+atom,-compound,+options)\n\tparse_csv_file/2\t\t\t# parse_csv_file(+filename,+options)\n\nWhere options can be:\n\n\ttrim(Boolean)\t\t\t\t# default false, trims leading and trailing whitespace\n\tnumbers(Boolean)\t\t\t# default false, converts integers and floats\n\theader(Boolean)\t\t\t\t# default false, skip first (header) line in file\n\tcomments(Boolean)\t\t\t# default false, skip lines beginning with comment character in file\n\tcomment(Char)\t\t\t\t# default '#', set the comment character\n\tstrings(Boolean)\t\t\t# default depends on type of input (atom or string)\n\tarity(Integer)\t\t\t\t# default to not checking arity, otherwise throw domain_error\n\tassert(Boolean)\t\t\t\t# default false, assertz to database instead (assumed for files, needs a functor)\n\tfunctor(Atom)\t\t\t\t# default output is a list, create a structure (mandatory for files and with assert)\n\tquote(Char)\t\t\t\t\t# default to double-quote\n\tsep(Char)\t\t\t\t\t# default to comma for .csv or unknown files \u0026 TAB for .tsv files\n\nWriting:\n\n\twrite_csv_file/3\t\t\t# write_csv_file(+filename,+list,+options)\n\nWhere options can be:\n\n\tappend(Boolean)\t\t\t\t# default is to truncate file, or append to file\n\tstrings(Boolean)\t\t\t# default depends on type of input (atom or string)\n\tsep(Char)\t\t\t\t\t# default to comma for .csv or unknown files \u0026 TAB for .tsv files\n\nExamples...\n\n```console\n\t? L=[[\"1 1\",12,'1 3'],[],['21','','23']], write_csv_file('x.csv',L,[]).\n\n\t$ cat x.csv\n\t\"1 1\",12,1 3\n\n\t21,,23\n\n\t?- Row=[\"1 1\",12,'1 3'], L=[Row], write_csv_file('x.csv',L,[]).\n\n\t$ cat x.csv\n\t\"1 1\",12,1 3\n\n\t?- parse_csv_line('123,2.345,3456789',T).\n\t   T = ['123','2.345','3456789'].\n\t?- parse_csv_line(\"123,2.345,3456789\",T).\n\t   T = [\"123\",\"2.345\",\"3456789\"].\n\t?- parse_csv_line('123,2.345,3456789',T,[functor(f)]).\n\t   T = f('123','2.345','3456789').\n\t?- parse_csv_line('123,2.345,3456789',T,[functor(f),numbers(true)]).\n\t   T = f(123,2.345,3456789).\n\t?- parse_csv_line('abc, abc, a b c ',T).\n\t   T = [abc,' abc',' a b c '].\n\t?- parse_csv_line('abc, abc, a b c ',T,[trim(true)]).\n\t   T = [abc,abc,'a b c'].\n\t?- parse_csv_line('123,2.345,3456789',T,[functor(f),numbers(true),assert(true)]).\n\t   true.\n\t?- f(A,B,C).\n\t   A = 123, B = 2.345, C = 3456789.\n\t?- time(parse_csv_file('../logtalk3/library/csv/test_files/tickers.csv',[functor(f),quote('\\'')])).\n\t% Parsed 35193 lines\n\t% Time elapsed 0.096s, 3 Inferences, 0.000 MLips)\n\t\t  true.\n\t?- f(A,B,C,D,E,F).\n\t   A = '1125:HK', B = 'OTCGREY', C = 'Stock', D = 'USD', E = '1999-06-22', F = '2019-10-22'\n\t;  A = '6317:TK', B = 'PINK', C = 'Stock', D = 'USD', E = '2018-06-27', F = '2020-03-02'\n\t;  A = 'A', B = 'NYSE', C = 'Stock', D = 'USD', E = '1999-11-18', F = '2021-06-25'\n\t;  A = 'AA', B = 'NYSE', C = 'Stock', D = 'USD', E = '2016-11-01', F = '2021-06-25'\n\t;  A = 'AA-W', B = 'NYSE', C = 'Stock', D = 'USD', E = '2016-10-18', F = '2016-11-08'\n\t;  A = 'AAA', B = 'NYSEARCA', C = 'ETF', D = 'USD', E = '2020-09-09', F = '2021-06-25'\n\t;\n```\n\n\nApplication maps (dictionaries)\n===============================\n\nMaps use atomic key/value pairs only and are represented as\npseudo-streams:\n\n\tmap_create/2\t\t\t\t\t# map_create(-skiplist,+opts)\n\tmap_create/1\t\t\t\t\t# map_create(-skiplist)\n\tmap_set/3\t\t\t\t\t\t# map_set(+skiplist,+key,+value)\n\tmap_get/3\t\t\t\t\t\t# map_get(+skiplist,+key,?value)\n\tmap_del/2\t\t\t\t\t\t# map_del(+skiplist,+key)\n\tmap_count/2\t\t\t\t\t\t# map_count(+skiplist,-count)\n\tmap_list/2\t\t\t\t\t\t# map_list(+skiplist,?list)\n\tmap_close/1\t\t\t\t\t\t# map_close(+skiplist)\n\n```console\n\t$ tpl\n\t?- map_create(S,[alias(foo)]).\n\t   S = \u003c$stream\u003e(4).\n\t?- map_set(foo,1,111), map_set(foo,two,222), map_set(foo,3,333).\n\t   true.\n\t?- map_get(foo,3,V).\n\t   V = 333.\n\t?- map_del(foo,3).\n\t   true.\n\t?- map_list(foo,L).\n\t   L = [1=111,two=222].\n\t?- map_close(foo).\n\t   true.\n```\n\nMaps can store virtually unlimited amounts of volatile data in\nan efficient indexed manner.\n\nMaps don't require syntactic extensions to Prolog as found in\nother non-standard systems.\n\nA possible future extension would be to load a CSV file directly\nin a very efficient manner.\n\n\nHTTP 1.1\n========\n\n\t:- use_module(library(http)).\n\n\thttp_get/3\t\t\t\t# http_get(Url, Data, Opts)\n\thttp_post/4\t\t\t\t# http_post(Url, Data, Opts)\n\thttp_patch/4\t\t\t# http_patch(Url, Data, Opts)\n\thttp_put/4\t\t\t\t# http_put(Url, Data, Opts)\n\thttp_delete/3\t\t\t# http_delete(Url, Data, Opts)\n\thttp_server/2\t\t\t# http_server(Goal,Opts),\n\thttp_request/5\t\t\t# http_request(S, Method, Path, Ver, Hdrs)\n\n```console\n\t?- http_get(\"https://github.com/trealla-prolog/trealla\", Data, [status_code(Code)]).\n\t   Data = \"\\n\\n\\n\\n\\n\\n\u003c!DOCTYPE html\u003e\\n\u003chtml\\n\"||... , Code = 200.\n```\n\nA server *Goal* takes a single arg, the connection stream.\n\n\nNetworking\t\t\t\t\t##EXPERIMENTAL##\n==========\n\n\t'$http_location'/2         # '$http_location'(?list,?url)\n\t'$parse_url'/2             # '$parse_url'(?url,?list)\n\n```console\n\t$ tpl\n\t?- '$parse_url'('http://www.xyz.org:81/hello?msg=Hello+World%21\u0026foo=bar#xyz',P).\n\t   P = [search([msg='Hello World!',foo=bar]),protocol(http),host('www.xyz.org'),port(81),path('/hello'),fragment(xyz)].\n\t?- '$parse_url'(U,[search([msg='Hello World!',foo=bar]),protocol(http),host('www.xyz.org'),port(81),path('/hello'),fragment(xyz)]).\n\t   U = 'http://www.xyz.org:81/hello?msg=Hello+World%21\u0026foo=bar#xyz'.\n\t?-\n```\n\n\t'$server'/2                # '$server'(+host,-stream)\n\t'$server'/3                # '$server'(+host,-stream,+list)\n\t'$accept'/2                # '$accept'(+stream,-stream)\n\t'$client'/2                # '$client'(+url,-stream)\n\t'$client'/4                # '$client'(+url,-host,-path,-stream)\n\t'$client'/5                # '$client'(+url,-host,-path,-stream,+list)\n\nThe options list can include *udp(bool)* (default is false),\n*nodelay(bool)* (default is true), *ssl(bool)* (default is false)\nand *certfile(filespec)*.\n\nAdditional server options can include *keyfile(filespec)*. If just\none concatenated file (keyfile+certfiles) is supplied, use\n*keyfile(filespec)* only.\n\nOptional schemes 'unix://', 'http://' (the default) and 'https://'\ncan be provided in the client URL.\n\nWith *'$bread'/3* the 'len' arg can be an integer \u003e 0 meaning return that\nmany bytes, = 0 meaning return whatever is there (if non-blocking) or\na var meaning return all bytes until end end of file,\n\n\nSimple regular expressions\n==========================\n\nThis is meant as a place-holder until a proper regex package is included.\n\n\tsre_compile/2\t\t\t\t# sre_compile(+pattern,-reg)\n\tsre_matchp/4\t\t\t\t# sre_matchp(+reg,+text,-match,-rest)\n\tsre_substp/4\t\t\t\t# sre_substp(+reg,+text,-prefix,-rest)\n\n\tsre_match/4\t\t\t\t\t# sre_match(+pattern,+text,-match,-rest)\n\tsre_match_all/3\t\t\t\t# sre_matchall(+pattern,+text,-list)\n\tsre_match_all_pos/3\t\t\t# sre_matchall_pos(+pattern,+text,-pairs)\n\n\tsre_match_all_in_file/3\t\t# sre_matchall_in_file(+pattern,+filename,-list)\n\tsre_match_all_pos_in_file/3 # sre_matchall_pos_in_file(+pattern,+filename,-pairs)\n\n\tsre_subst/4\t\t\t\t\t# sre_subst(+pattern,+text,-prefix,-rest)\n\tsre_subst_all/4\t\t\t\t# sre_subst(+pattern,+text,+subst,-text)\n\n\tsre_subst_all_in_file/4\t\t# sre_subst_in_file(+pattern,+filename,+subst,-text)\n\n```\n\t * Supports:\n\t * ---------\n\t *   '.'        Dot, matches any character\n\t *   '^'        Start anchor, matches beginning of string\n\t *   '$'        End anchor, matches end of string\n\t *   '*'        Asterisk, match zero or more (greedy)\n\t *   '+'        Plus, match one or more (greedy)\n\t *   '?'        Question, match zero or one (non-greedy)\n\t *   '[abc]'    Character class, match if one of {'a', 'b', 'c'}\n\t *   '[^abc]'   Inverted class, match if NOT one of {'a', 'b', 'c'}\n\t *   '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z }\n\t *   '\\s'       Whitespace, \\t \\f \\r \\n \\v and spaces\n\t *   '\\S'       Non-whitespace\n\t *   '\\w'       Alphanumeric, [a-zA-Z0-9_]\n\t *   '\\W'       Non-alphanumeric\n\t *   '\\d'       Digits, [0-9]\n\t *   '\\D'       Non-digits\n```\n\nFor example...\n\n```console\n\t?- sre_compile(\"d.f\", Reg), sre_matchp(Reg, \"abcdefghi\", M, Rest).\n\t   Reg = \u003c$blob\u003e(0x6AC5AAF0), M = \"def\", Rest = \"ghi\".\n\n\t?- sre_match(\"d.f\", \"abcdefghi\", M, Rest).\n\t   M = \"def\", Rest = \"ghi\".\n\n\t?- sre_match_all(\"d.f\", \"xdafydbfzdcf-\", L).\n\t   L = [\"daf\",\"dbf\",\"dcf\"].\n\n\t?- sre_match_all_pos(\"d.f\", \"xdafydbfzdcf-\", L).\n\t   L = [1-3,2-3,3-3].\n\n\t?- sre_match_all(\"d[^c]f\", \"xdafydbfzdcfxddf-\", L).\n\t   L = [\"daf\",\"dbf\",\"ddf\"].\n\n\t?- sre_subst(\"d.f\", \"xdafydbfzdcf-\", P, L).\n\t   P = \"x\", L = \"ydbfzdcf-\".\n\n\t?- sre_subst_all(\"d.f\", \"xdafydbfzdcf-\", \"$\", L).\n\t   L = \"x$y$z$-\".\n\n\t?- sre_match_all(\"\\\\S\", \"Needle In A Haystack\", L).\n\t   L = [\"N\",\"e\",\"e\",\"d\",\"l\",\"e\",\"I\",\"n\",\"A\",...].\n\n\t?- sre_match_all_pos(\"\\\\s\", \"Needle In A Haystack\", L).\n\t   L = [6-1,9-1,11-1].\n\n\t?- time(sre_match_all_in_file(\"t\\\\We\",'thesaurus.txt',L)),\n\t\tlength(L,Len),\n\t\tformat(\"Occurrs: ~w times~n\",[Len]),\n\t\thalt.\n\tTime elapsed 0.0463s\n\tOccurrs: 749 times\n```\n\nNote: if no match is found the returned *match*, *text* (and *list*) is *[]*\nindicating an empty string.\n\nNote: if the input *text* arg is a string then the output *text* arg\nis a no-copy slice of the string. So if the input is a memory-mapped\nfile then regex searches can be performed quickly and efficiently over\nhuge files.\n\n\nForeign Function Interface (libffi)\n===================================\n\nAllows the loading of dynamic libraries and calling of foreign functions\nwritten in C from within Prolog...\n\n\t'$dlopen'/3 \t\t\t# '$dlopen(+name, +flag, -handle)\n\nThese predicates register a foreign function as a builtin and use a\nwrapper to validate arg types at call/runtime...\n\n\t'$register_function'/4\t\t# '$ffi_reg'(+handle,+symbol,+types,+ret_type)\n\t'$register_predicate'/4\t\t# '$ffi_reg'(+handle,+symbol,+types,+ret_type)\n\nThe allowed types are\n*sint8*, *sint16*, *sint32*, *sint64*, *sint* (native *signed int*),\n*uint8*, *uint16*, *uint32*, *uint64*, *uint* (native *unsigned int*),\n*ushort*, *sshort*, *float*, *double*,\n*bool*, (use integer 0/1 to align with C *bool* pseudo-type)\n*void* (a return type only),\n*cstr* (a char pointer),\nand *ptr* (for arbitrary pointers/handles).\n\nAssuming the following C-code in *samples/foo.c*:\n\n```c\n\tdouble foo(double x, int64_t y)\n\t{\n\t\treturn pow(x, (double)y);\n\t}\n\n\tint bar(double x, int64_t y, double *result)\n\t{\n\t\t*result = pow(x, (double)y);\n\t\treturn 0;\n\t}\n\n\tchar *baz(const char *x, const char *y)\n\t{\n\t\tchar *s = TPL_malloc(strlen(x) + strlen(y) + 1);\n\t\tstrcpy(s, x);\n\t\tstrcat(s, y);\n\t\treturn s;\n\t}\n```\n\n```console\n\t$ gcc -fPIC -c foo.c\n\t$ gcc -shared -o libfoo.so foo.o\n```\n\nRegister a builtin function...\n\n```console\n\t?- '$dlopen'('samples/libfoo.so', 0, H),\n\t\t'$register_function'(H, foo, [double, sint64], double).\n\t   H = 94051868794416.\n\t?- R is foo(2.0, 3).\n\t   R = 8.0.\n\t?- R is foo(abc,3).\n\t   error(type_error(float,abc),foo/2).\n```\n\nRegister a builtin predicate...\n\n```console\n\t?- '$dlopen'('samples/libfoo.so', 0, H),\n\t\t'$register_predicate'(H, bar, [double, sint64, -double], sint64),\n\t\t'$register_predicate'(H, baz, [cstr, cstr], cstr),\n\t   H = 94051868794416.\n\t?- bar(2.0, 3, X, Return).\n\t   X = 8.0, Return = 0.\n\t?- baz('abc', '123', Return).\n\t   Return = abc123.\n```\n\nNote: the foreign function return value is passed as an extra argument\nto the predicate call, unless it was specified to be of type *void*.\n\n\nForeign Module Interface (libffi)\n=================================\n\nThis is a simplified interface to FFIs inspired by Adrián Arroyo Calle\nand largely supercedes the implementation given above.\n\n\tforeign_struct(+atom, +list)\n\tuse_foreign_module(+atom, +list)\n\nFor example...\n\n```prolog\n\t:- use_foreign_module('samples/libfoo.so', [\n\t\tbar([double, sint64, -double], sint64),\n\t\tbaz([cstr, cstr], cstr)\n\t]).\n```\n\nSee the *library/raylib.pl* and *samples/test_raylib.pl* for an example\nusage including passing and returning structs by value.\n\nSee the *library/curl.pl* and *samples/test_curl.pl* for an example\nusage downloading a file.\n\nThis is an example using SQLITE. Given the code in *samples/sqlite3.pl*...\n\n```prolog\n\t:- use_module(library(sqlite3)).\n\n\trun :-\n\t\ttest('samples/sqlite3.db', 'SELECT * FROM company').\n\n\ttest(Database, Query) :-\n\t\tsqlite_flag('SQLITE_OK', SQLITE_OK),\n\t\tsqlite3_open(Database, Connection, Ret), Ret =:= SQLITE_OK,\n\t\tbagof(Row, sqlite3_query(Connection, Query, Row, _), Results),\n\t\twriteq(Results), nl.\n```\n\nRun...\n\n```console\n\t$ tpl -g run,halt samples/sqlite3.pl\n\t[[1,'Paul',32,'California',20000.0],[2,'Allen',25,'Texas',15000.0],[3,'Teddy',23,'Norway',20000.0],[4,'Mark',25,'Rich-Mond ',65000.0],[5,'David',27,'Texas',85000.0],[6,'Kim',22,'South-Hall',45000.0]]\n```\n\n\nISO Prolog Multithreading\n=========================\n\nStart independent (shared state) Prolog queries as dedicated POSIX\nthreads and communicate via message queues. Note: the database *is*\nshared. These predicates conform to the *ISO Prolog multithreading\nsupport* standards proposal (ISO/IEC DTR 13211–5:2007), now lapsed.\nNote: a thread is also a queue and a mutex. Note this is an expired\nISO standards proposal but is commonly supported.\n\n\tthread_create/3\t\t\t\t# thread_create(:callable,-thread,+opts)\n\tthread_create/2\t\t\t\t# thread_create(:callable,-thread)\n\tthread_signal/2\t\t\t\t# thread_signal(+thread,:callable)\n\tthread_join/2\t\t\t\t# thread_join(+thread,-term)\n\tthread_cancel/1\t\t\t\t# thread_cancel(+thread)\n\tthread_detach/1\t\t\t\t# thread_detach(+thread)\n\tthread_self/1\t\t\t\t# thread_self(-thread)\n\tthread_exit/1\t\t\t\t# thread_exit(+term)\n\tthread_sleep/1\t\t\t\t# thread_sleep(+integer)\n\tthread_yield/0\t\t\t\t# thread_yield\n\tthread_property/2\t\t\t# thread_property(+thread,+term)\n\tthread_property/1\t\t\t# thread_property(+term)\n\n\tthread_send_message/2\t\t# thread_send_message(+queue,+term)\n\tthread_send_message/1\t\t# thread_send_message(+term)\n\tthread_get_message/2\t\t# thread_get_message(+queue,?term)\n\tthread_get_message/1\t\t# thread_get_message(?term)\n\tthread_peek_message/2\t\t# thread_peek_message(+queue,?term)\n\tthread_peek_message/1\t\t# thread_peek_message(?term)\n\nWhere 'opts' can be *alias(+atom)*, *at_exit(:term)* and/or *detached(+boolean)*\n(the default is *NOT* detached, ie. joinable).\nNote: `thread_cancel/1` is dangerous and should be avoided, it does\nnot exist in some other Prologs and does not rightly belong in any standards\nproposal.\n\nThese are non-standard but *SWI-Prolog* compatible:\n\n\tthread_join/1\t\t\t\t# thread_join(+thread)\n\tthread_get_message/3\t\t# thread_get_message(+queue,?term,+opts)\n\nWhere 'opts' can be *timeout(+float)* to specify a timeout in seconds.\n\nCreate a stand-alone message queue.\nNote: a queue is also a mutex.\n\n\tmessage_queue_create/2\t\t# message_queue_create(-queue,+opts)\n\tmessage_queue_create/1\t\t# message_queue_create(-queue)\n\tmessage_queue_destroy/1\t\t# message_queue_destroy(+queue)\n\tmessage_queue_property/2\t# message_queue_property(+queue,+term)\n\nWhere 'opts' can be *alias(+atom)*.\n\nCreate a stand-alone mutex...\n\n\tmutex_create/2\t\t\t\t# mutex_create(-mutex,+opts)\n\tmutex_create/1\t\t\t\t# mutex_create(-mutex)\n\tmutex_destroy/1\t\t\t\t# mutex_destroy(+mutex)\n\tmutex_property/2\t\t\t# mutex_property(+mutex,+term)\n\twith_mutex/2\t\t\t\t# with_mutex(+mutex,:callable)\n\n\tmutex_trylock/1\t\t\t\t# mutex_trylock(+mutex)\n\tmutex_lock/1\t\t\t\t# mutex_lock(+mutex)\n\tmutex_unlock/1\t\t\t\t# mutex_unlock(+mutex)\n\tmutex_unlock_all/0\t\t\t# mutex_unlock_all\n\nWhere 'opts' can be *alias(+atom)*. Use of mutexes other than\n*with_mutex/2* should generally be avoided.\n\nFor example...\n\n\t```console\n\t?- thread_create((format(\"thread_hello~n\",[]),sleep(1),format(\"thread_done~n\",[]),thread_exit(99)), Tid, []), format(\"joining~n\",[]), thread_join(Tid,Status), format(\"join_done~n\",[]).\n\tjoining\n\tthread_hello\n\tthread_done\n\tjoin_done\n\t   Tid = 1, Status = exited(99).\n\t?-\n\t```\n\nProlog instances\t\t\t##EXPERIMENTAL##\n================\n\nStart independent (no shared state) Prolog instances as dedicated\npre-emptive threads and communicate via message queues. Each thread\nhas it's own message queue associated with it. Note: the database\nis *not* shared. For shared state consider using the blackboard.\n\n\tpl_thread/3\t\t\t\t# pl_thread(-thread,+filename,+options)\n\tpl_thread/2\t\t\t\t# pl_thread(-thread,+filename)\n\nWhere 'options' can be (currently just) *alias(+atom)*.\n\n\tpl_msg_send/2\t\t\t# pl_msg_send(+thread,+term)\n\tpl_msg_recv/2\t\t\t# pl_msg_recv(-thread,-term)\n\n\nFor example...\n\n```console\n\t$ cat samples/thread_calc.pl\n\t:- initialization(main).\n\n\t% At the moment we only do sqrt here...\n\n\tmain :-\n\t\twrite('Calculator running...'), nl,\n\t\trepeat,\n\t\t\tpl_msg_recv(Tid, Term),\n\t\t\tTerm = sqrt(X, Y),\n\t\t\tY is sqrt(X),\n\t\t\tpl_msg_send(Tid, Term),\n\t\t\tfail.\n\n\t$ tpl\n\t?- pl_thread(_, 'samples/thread_calc.pl', [alias(calc)]).\n\tCalculator running...\n\t?- Term = sqrt(2, V),\n\t\tpl_msg_send(calc, Term),\n\t\tpl_msg_recv(_, Term).\n\t   Term = sqrt(2,1.4142135623731), V = 1.4142135623731.\n\t?-\n```\n\nConcurrent Tasks\t\t\t\t\t\t##EXPERIMENTAL##\n================\n\nCo-operative multitasking is available in the form of light-weight\ncoroutines that run until they yield either explicitly or implicitly\n(when waiting on an event of some kind). They are called a `task` here.\n\n\tcall_task/[1-n]\t        # concurrent form of call/1-n\n\ttasklist/[2-8]          # concurrent form of maplist/1-n\n\nAn example:\n\n```prolog\n\t:-use_module(library(http)).\n\n\tgeturl(Url) :-\n\t\thttp_get(Url,_Data,[status_code(Code),final_url(Location)]),\n\t\tformat(\"Job [~w] ~w ==\u003e ~w done~n\",[Url,Code,Location]).\n\n\t% Fetch each URL in list sequentially...\n\n\ttest54 :-\n\t\tL = ['www.google.com','www.bing.com','www.duckduckgo.com'],\n\t\tmaplist(geturl,L),\n\t\twrite('Finished\\n').\n\n\t$ tpl samples/test -g \"time(test54),halt\"\n\tJob [www.google.com] 200 ==\u003e www.google.com done\n\tJob [www.bing.com] 200 ==\u003e www.bing.com done\n\tJob [www.duckduckgo.com] 200 ==\u003e https://duckduckgo.com done\n\tFinished\n\tTime elapsed 0.663 secs\n\n\t% Fetch each URL in list concurrently...\n\n\ttest56 :-\n\t\tL = ['www.google.com','www.bing.com','www.duckduckgo.com'],\n\t\ttasklist(geturl,L),\n\t\twrite('Finished\\n').\n\n\t$ tpl samples/test -g \"time(test56),halt\"\n\tJob [www.duckduckgo.com] 200 ==\u003e https://duckduckgo.com done\n\tJob [www.bing.com] 200 ==\u003e www.bing.com done\n\tJob [www.google.com] 200 ==\u003e www.google.com done\n\tFinished\n\tTime elapsed 0.33 secs\n```\n\nLinda Co-ordination Language\t\t\t##EXPERIMENTAL##\n============================\n\nImplements a toy (local-only) version of Linda using tasks. See:\n[swi-prolog](https://www.swi-prolog.org/pldoc/man?section=tipc-linda-clients).\n\n\tlinda_eval/1                    # linda_eval(:goal)\n\tout/1                           # out(+tuple)\n\tin/1                            # in(?tuple)\n\trd/1                            # rd(?tuple)\n\tinp/1                           # inp(?tuple)\n\trdp/1                           # rdp(?tuple)\n\tbagof_in_noblock/3              # bagof_in_noblock(+term,+tuple,?list)\n\tbagof_rd_noblock/3              # bagof_rd_noblock(+term,+tuple,?list)\n\twait/0\n\tend_wait/0\n\nFor example:\n\n```prolog\n\t:- use_module(library(linda)).\n\t:- initialization(main).\n\n\tmain :-\n\t\tlinda_eval(consumer('A')),\n\t\tlinda_eval(consumer('B')),\n\t\tlinda_eval(producer),\n\t\twait,\n\t\tin(producer),               % verify it finished normally\n\t\twriteq(done), nl,\n\t\thalt.\n\n\tproducer :-\n\t\tbetween(1, 10, I),\n\t\t\tout({msg:I}),\n\t\t\tsleep(0.25),\n\t\t\tfail.\n\tproducer :-\n\t\tforall(rdp({msg:_}), sleep(0.001)),\n\t\tend_wait.\n\n\tconsumer(N) :-\n\t\tin({msg:I}),\n\t\twrite(['consumer',N,'got=',I]), nl,\n\t\trandom(R),\n\t\tsleep(R),\n\t\tfail.\n```\n\n```console\n\t$ tpl samples/test_linda.pl\n\t[consumer,B,got=,1]\n\t[consumer,B,got=,2]\n\t[consumer,B,got=,3]\n\t[consumer,A,got=,4]\n\t[consumer,B,got=,5]\n\t[consumer,A,got=,6]\n\t[consumer,B,got=,7]\n\t[consumer,A,got=,8]\n\t[consumer,A,got=,9]\n\t[consumer,B,got=,10]\n\tdone\n```\n\nConcurrent Futures\t\t\t\t\t\t##EXPERIMENTAL##\n==================\n\nInspired by [Tau-Prolog](http://tau-prolog.org/documentation#concurrent)\nconcurrent futures. Uses co-operative tasks.\n\n\tfuture/3          # Make a Future from a Prolog goal.\n\tfuture_all/2      # Make a Future that resolves to a list of the results of an input list of futures.\n\tfuture_any/2      # Make a Future that resolves as soon as any of the futures in a list succeeds.\n\tfuture_cancel/1   # Cancel unfinished future.\n\tfuture_done/1     # Check if a future finished.\n\tawait/2           # Wait for a Future.\n\nFor example:\n\n```prolog\n\t:- use_module(library(concurrent)).\n\t:- use_module(library(http)).\n\n\ttest :-\n\t\tfuture(Status1, geturl(\"www.google.com\", Status1), F1),\n\t\tfuture(Status2, geturl(\"www.bing.com\", Status2), F2),\n\t\tfuture(Status3, geturl(\"www.duckduckgo.com\", Status3), F3),\n\t\tfuture_all([F1,F2,F3], F),\n\t\tawait(F, StatusCodes),\n\t\tC = StatusCodes.\n```\n\nSee `samples/test_concurrent.pl`.\n\n\nEngines\t\t\t\t\t\t##EXPERIMENTAL##\n=======\n\nInspired by [*SWI-Prolog*](https://www.swi-prolog.org/pldoc/man?section=engine-predicates)\nengines. Uses co-operative tasks.\n\n\tengine_create/[3,4]\n\tengine_next/2\n\tengine_yield/1\n\tengine_post/[2,3]\n\tengine_fetch/1\n\tengine_self/1\n\tis_engine/1\n\tcurrent_engine/1\n\tengine_destroy/1\n\nFor example:\n```\n\t✗ cat find.pl\n\tfind_at_most(N, Template, Goal, List) :-\n\t\tengine_create(Template, Goal, Engine),\n\t\tcollect_at_most(N, Engine, List0),\n\t\tengine_destroy(Engine),\n\t\tList = List0.\n\n\tcollect_at_most(N, Engine, [X| Xs]) :-\n\t\tN \u003e 0,\n\t\tengine_next(Engine, X),\n\t\t!,\n\t\tM is N - 1,\n\t\tcollect_at_most(M, Engine, Xs).\n\tcollect_at_most(_, _, []).\n\t✗ tpl -q find.pl\n\t?- find_at_most(5, I, between(1,1000,I), Sols).\n\t   Sols = [1,2,3,4,5].\n\t?- ^D%\n```\n\nCompile to standalone\t\t##EXPERIMENTAL##\n=====================\n\n```\n\t✗ cat samples/main.pl\n```\n\n```prolog\n\t:- initialization(main).\n\n\tmain :-\n\t\t\twrite('Hello, world!'), nl,\n\t\t\thalt.\n```\n\n```\n\t✗ make compile main=samples/main.pl\n\t✗ ./tpl\n\tHello, world!\n```\n\n\nProfile\n=======\n\nWhy did I put this here?\n\n```console\n\t$ time tpl -q -g 'main,statistics(profile,_),halt' -f ~/trealla/samples/out.pl 2\u003eout.csv\n\t$ head -1 out.csv \u003eout_sorted.csv \u0026\u0026 tail -n+2 out.csv | sort -k 3 -t ',' -n -r \u003e\u003e out_sorted.csv\n\t$ cat out_sorted.csv\n\t#functor/arity,match_attempts,matched,tcos\n\t'member_/3',20505037,20036023,19362515\n\t'can_step/5',1149136,288705,189915\n\t'can_move/5',164848,98905,32873\n\t'strength/4',1074794,63382,31691\n\t'minus_one/2',1621942,1621942,0\n\t'make_move/6',1086892,1086892,0\n\t'member_/3',20709531,730369,0\n\t'member/2',673508,673508,0\n\t'occupied_by/4',673316,673316,0\n\t...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrealla-prolog%2Ftrealla","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrealla-prolog%2Ftrealla","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrealla-prolog%2Ftrealla/lists"}