ITADN
mthom/scryer-prolog
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

Scryer Prolog

Scryer Prolog 旨在成为 ISO Prolog 领域的 GHC(即 Haskell 领域的 GHC):一个开源的、工业级强度的生产环境,同时也是逻辑与约束编程前沿研究的试验平台,其本身使用高级语言编写。

Scryer Prolog 通过了所有 语法一致性variable_names/1dif/2 测试。

该项目的首页是:https://www.scryer.pl

Scryer Logo: Cryer

阶段 1

在 Rust 中实现 Warren 抽象机器,按照 Warren's Abstract Machine: A Tutorial Reconstruction 中语言的演进顺序进行。

阶段 1 已完成,因为 Scryer Prolog 以某种形式实现了 WAM 书籍中的所有 内容,包括列表、切割、Debray 分配、首参数索引、尾调用优化和合取查询。

阶段 2

扩展 Scryer Prolog 以包含以下功能,以及其他功能:

  • 将 call/N 作为内置元谓词。
  • 符合 ISO Prolog 标准的 throw/catch。
  • 具有所有固定性的内置和用户定义运算符,支持自定义 结合性和优先级。
  • 大整数、有理数和浮点算术。
  • 内置控制运算符(,, ;, ->, 等)。
  • 经过修订的、不算糟糕的模块系统。
  • 用于列表处理和顶层声明式控制的内置谓词 (setup_call_cleanup/3, call_with_inference_limit/3, 等)
  • 字符串的默认表示为字符列表,使用打包的 内部表示。
  • term_expansion/2goal_expansion/2
  • 确定子句文法。
  • 使用 SICStus Prolog 接口和 语义的带属性变量。添加像 dif/2, freeze/2 等协程 对于带属性变量来说很直接。
    • verify_attributes/3 的支持
    • attribute_goals/2project_attributes/2 的支持
    • call_residue_vars/2
  • if_/3 及相关谓词,遵循论文 "Indexing dif/2" 的发展。
  • 所有解谓词(findall/{3,4}, bagof/3, setof/3, forall/2)。
  • 子句创建和销毁(asserta/1, assertz/1, retract/1, abolish/1),具有逻辑更新语义。
  • 通过 bb_get/2 bb_put/2(不可回溯)和 bb_b_put/2 (可回溯)实现的可回溯和不可回溯全局变量。
  • 基于 reset/3, shift/1 的受限延续(记录于 "Delimited Continuations for Prolog")。
  • 基于受限延续的表化库 (记录于“作为库的表格化与分隔控制”)。
  • 使用打包的内部表示,将字符串重新表示为字符的差异列表。
  • clp(B) 和 clp(ℤ) 作为内置库。
  • 流以及用于流控制的谓词。
    • 一个将 TCP 连接表示为流的简单套接字库。
  • 增量编译和加载过程,新编写, 主要使用 Prolog 实现。
  • 对 WAM 编译器和堆表示的改进:
    • 将围绕内联半确定性谓词 (atomvar 等)的选点替换为 if/else 阶梯。(进行中
    • 内联所有内置函数和系统调用指令。
    • 大幅减少用于编译析取式的指令数量。
    • 将短原子存储到堆单元中,而不写入原子表。
  • 对所有参数可配置的 JIT/按需索引 (记录于“Prolog 子句的需求驱动索引”)。(进行中
  • 满足“Prolog 中的精确垃圾回收”中五个属性的压缩式垃圾回收器。(进行中

阶段 3

使用已完成的代码生成器生成的 WAM 代码,以获取 JIT 编译并执行的 Prolog 程序。如何从 WAM 代码获取 汇编代码的问题,我仍在考虑中。

我希望使用 Scryer Prolog 作为低级别(并且 理想情况下,非常快)的 Shen 实现的逻辑引擎。

锦上添花的功能

目前没有任何计划实现这些功能,但它们在未来 可能很有用。对于任何想要 为 Scryer Prolog 贡献代码的人来说,它们将是一个很好的项目。

  1. 实现 Peter van Roy 的论文中描述的全局分析技术,“Can Logic Programming Execute as Fast as Imperative Programming?"

  2. 添加 unum 表示法和算术运算,使用现有的 unum 实现或临时实现。Unums 在 Gustafson 的书《The End of Error》中有描述。

  3. 添加并发表来管理对原子和 字符串的共享引用。

安装 Scryer Prolog

二进制文件

多个平台的预编译二进制文件可供下载 于:

https://github.com/mthom/scryer-prolog/releases/latest

原生编译

首先,使用您偏好的方法安装最新稳定版的 Rust。Scryer 倾向于使用较新 Rust 版本中的特性,而 Linux 发行版、Macports 等中的 Rust 软件包往往滞后。rustup 会将您的 Rust 更新到最新稳定版;在使用 rustup 之前, 应卸载系统中已存在的任何 Rust 发行版。

[!NOTE] 所需的最小 rust 工具链版本可在 Cargo.tomlpackage.rust-version 键下找到。 该值的准确性已在 CI 中验证

从本地 git 检出

$> git clone https://github.com/mthom/scryer-prolog
$> cd scryer-prolog
$> cargo build --release

--release 标志执行各种优化,生成 更快的可执行文件。

编译完成后,可执行文件 scryer-prolog 位于 目录 target/release 中,可以调用以运行系统。

通过 cargo install

从 git

cargo install --locked --git https://github.com/mthom/scryer-prolog.git

之后,scryer-prolog 二进制文件将位于 $HOME/.cargo/bin 目录中,该目录通常在安装 rust 工具链时被添加到你的 PATH 中。

从 Crates.io Crates.io Version Crates.io MSRV

[!NOTE] crates.io 上的最新版本可能显著落后于 git 仓库中可用的版本 本节标题中的 crates.io 徽章是链接到 crates.io 页面的链接。 本节标题中的 msrv 徽章引用了编译最新 crates.io 版本所需的最低 rust 工具链版本

scryer-prolog 也在 crates.io 上发布,并且可以通过以下方式安装

cargo install --locked scryer-prolog

Windows 注意事项

在 Windows 上,在 MSYS2 环境中构建 Scryer Prolog 更为简单,因为某些 crate 可能需要原生 C 编译。然而, 生成的二进制文件运行时无需 MSYS2。在 shell 中执行 Scryer 时,建议使用比 mintty(MSYS2 默认 shell)更高级的 shell。Windows Terminal 可以正常工作。

要构建 Windows 安装程序,首先需要以 release 模式编译 Scryer Prolog,然后,在安装 WiX Toolset 后,执行:

candle.exe scryer-prolog.wxs
light.exe scryer-prolog.wixobj

它将生成一个非常基础的 MSI 文件,该文件安装主可执行文件并在开始菜单中创建一个快捷方式。可以通过双击进行安装。要卸载,请前往控制面板并按常规方式卸载。

构建 WebAssembly

Scryer Prolog 具有基本的 WebAssembly 支持。您可以按照 wasm-pack官方说明 安装 wasm-pack 并以您喜欢的方式构建它。

然而,目前不支持任何默认特性。禁用它们的推荐方式是向 wasm-pack 传递额外选项

例如,如果您想要一个不使用 webpack 等打包器的最小可用包,您可以这样做:

wasm-pack build --target web -- --no-default-features

然后会创建一个 pkg 目录,其中包含 webapp 所需的一切。您可以通过创建一个 html 文件来测试包是否成功构建,该文件改编自 wasm-bindgen官方示例,如下所示:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Scryer Prolog - Sudoku Solver Example</title>
    <script type="module">
        import initScryer, { MachineBuilder } from "./pkg/scryer_prolog.js";

        // Initialize Scryer Prolog with WASM
        const wasm = await fetch("./pkg/scryer_prolog_bg.wasm");
        const module = await WebAssembly.compile(await wasm.arrayBuffer());
        await initScryer(module);

        // Set up the Prolog machine
        const machine = new MachineBuilder().build();

        // Knowledge base: Sudoku rules and problem definition
        const kb = `
        :- use_module(library(format)).
        :- use_module(library(clpz)).
        :- use_module(library(lists)).

        sudoku(Rows) :-
          length(Rows, 9), maplist(same_length(Rows), Rows),
          append(Rows, Vs), Vs ins 1..9,
          maplist(all_distinct, Rows),
          transpose(Rows, Columns),
          maplist(all_distinct, Columns),
          Rows = [A,B,C,D,E,F,G,H,I],
          blocks(A, B, C),
          blocks(D, E, F),
          blocks(G, H, I).

        blocks([], [], []).
        blocks([A,B,C|T1], [D,E,F|T2], [G,H,I|T3]) :-
          all_distinct([A,B,C,D,E,F,G,H,I]),
          blocks(T1, T2, T3).

        problem(1, [[_,_,_,_,_,_,_,_,_],
                    [_,_,_,_,_,3,_,8,5],
                    [_,_,1,_,2,_,_,_,_],
                    [_,_,_,5,_,7,_,_,_],
                    [_,_,4,_,_,_,1,_,_],
                    [_,9,_,_,_,_,_,_,_],
                    [5,_,_,_,_,_,_,7,3],
                    [_,_,2,_,1,_,_,_,_],
                    [_,_,_,_,4,_,_,_,9]]).
      `;

        machine.consultModuleString("user", kb);

        // Run the query
        const query = "problem(1, Rows), sudoku(Rows), maplist(portray_clause, Rows).";
        const answers = machine.runQuery(query);

        const formattedSolutions = [];

        // Format the answers
        for (const solution of answers) {
            const rows = solution.bindings["Rows"].list;

            const grid = rows.map(row =>
                row.list.map(cell => cell.integer)
            );

            const formatted = grid.map(row => `[${row.join(", ")}]`).join("\n");
            formattedSolutions.push(formatted);
        }

        // Output results
        const solutionDiv = document.querySelector("#soduku-solution");
        for (const solution of formattedSolutions) {
            const newPre = document.createElement("pre");
            newPre.textContent = solution;
            solutionDiv.appendChild(newPre);
        }
    </script>
</head>

<body>
    <p>Sudoku solver returns:</p>
    <div id="soduku-solution">

    </div>
</body>

</html>

然后你可以使用你喜欢的 http 服务器(如 python -m http.servernpx serve)来提供该服务,并通过浏览器访问该页面。

Docker 安装

预构建的 Docker 镜像可在 Docker Hub 上获取latest 标签反映了 master 的状态,这可能是不稳定的。 此外,还有针对 Scryer 0.9.2 及更高版本发布的标签。 但请注意,目前基础镜像并未保持更新, 因此请警惕安全漏洞(参见 #2646)。

首先,在 Linux、 Windows 或 Mac 上安装 Docker

安装 Docker 后,你可以使用一条 命令下载并运行 Scryer Prolog:

$> docker run -it mjt128/scryer-prolog

要咨询你的 Prolog 文件,请将你的程序文件夹绑定挂载为 Docker 卷

$> docker run -v /home/user/prolog:/mnt -it mjt128/scryer-prolog
?- consult('/mnt/program.pl').
true.

这在 Windows 上同样有效:

$> docker run -v C:\Users\user\Documents\prolog:/mnt -it mjt128/scryer-prolog
?- consult('/mnt/program.pl').
true.

教程

Prolog 文件通过将其作为命令行参数指定来加载。例如,要加载 program.pl,请使用:

$> scryer-prolog program.pl

加载 Prolog 文件也称为“咨询”该文件。内置 谓词 consult/1 可用于在 Prolog 内部咨询文件:

?- consult('program.pl').

作为 consult/1 的缩写,你可以指定一个列表, 其中包含以原子形式给出的程序文件:

?- ['program.pl'].

特殊记号 [user] 用于从标准输入读取 Prolog 文本。例如,

?- [user].
hello(declarative_world).
hello(pure_world).

按下 RETURN 后按 Ctrl-d 会停止从 标准 输入读取并咨询输入的 Prolog 文本。

咨询程序后,您可以询问其定义的 谓词查询。例如,对于上面显示的程序:

?- hello(What).
   What = declarative_world
;  What = pure_world.

SPACE 显示更多答案(如果存在)。按 RETURN 或 . 中止搜索并返回到 顶层 提示符。按 f 显示到下一个 5 的倍数 的答案,按 a 显示所有答案。按 h 显示帮助 信息。

使用 TAB 在查询中补全原子和谓词名称。例如, 在咨询上述程序后,输入 decl 然后 按 TAB 将得到 declarative_world。反复按 TAB 以循环浏览替代补全项。

要退出 Scryer Prolog,使用标准谓词 halt/0

?- halt.

启动 Scryer Prolog

Scryer Prolog 可以通过命令行启动,通过指定 选项、文件和附加参数。所有组件均为可选:

scryer-prolog [OPTIONS] [FILES] [-- ARGUMENTS]

支持的选项如下:

   -h, --help             Display help message
   -v, --version          Print version information and exit
   -g, --goal GOAL        Run the query GOAL after consulting files
   -f                     Fast startup. Do not load initialization file (~/.scryerrc)
   --no-add-history       Prevent adding input to history file (~/.scryer_history)

所有指定的 Prolog 文件都会被咨询。

在 Prolog 文件之后,可以在命令行上指定应用程序特定的参数。这些参数可以通过谓词 argv/1 在 Prolog 应用程序内部访问,该谓词返回以字符串形式表示的参数列表。

https://github.com/mthom/scryer-prolog/issues/2170#issuecomment-1821713993 中所述,Prolog 文件也可以转换为 shell scripts

动态运算符

Scryer 支持动态运算符。使用具有通常优先级的内置算术运算符,

?- write_canonical(-5 + 3 - (2 * 4) // 8), nl.
-(+(-5,3),//(*(2,4),8))
   true.

可以使用 op 声明定义新的运算符。

首个已实例化参数索引

Scryer Prolog 在谓词 定义的所有子句中,对最左侧的非变量参数进行索引。我们将此策略称为 首个已实例化参数索引。

首个已实例化参数索引的一个关键动机是,为诸如 maplist/Nfoldl/N 这样的元谓词启用 索引,这些谓词的第一个参数是一个部分目标,在这些谓词的定义中是一个变量,因此不能用于索引。

例如,maplist/2 的一个自然定义如下:

maplist(_, []).
maplist(Goal_1, [L|Ls]) :-
        call(Goal_1, L),
        maplist(Goal_1, Ls).

在这种情况下,首先实例化的参数索引会自动使用 第二个 参数进行索引,从而防止了 具有固定长度列表(以及确定性目标)的调用产生选择点。 方便的是,在这种情况下,无需使用 参数顺序重新排列的辅助谓词即可受益于索引。

传统的第一个参数 索引自然作为 此策略的一个特例出现,如果谓词定义中的 任何子句都实例化了第一个参数。

字符串和部分字符串

字符串 的一种非常紧凑的内部表示是 Scryer Prolog 的关键 创新之一。这意味着在 Prolog 程序中 作为字符列表出现的项,由引擎以打包的 UTF-8 编码存储。

如果没有这项创新,在内存中存储字符列表 每个字符将使用一个 WAM 内存 单元,每个列表 构造器一个单元,并且列表中出现的每个尾部各占一个单元。由于 在 Scryer Prolog 实现的 WAM 中,一个单元占用 8 字节,因此打包表示 最多可将内存使用量减少 24 倍,并在创建和处理 字符串时相应地减少内存 访问。

Scryer Prolog 紧凑的内部字符串表示使其 非常适合 Prolog 最初开发时的用例: 高效且便捷的文本处理,特别是使用 library(dcgs)library(pio) 提供的确定性子句文法 (DCGs) 来透明地对文件应用 DCG。

在 Scryer Prolog 中,Prolog 标志 double_quotes 的默认值为 chars,这也是推荐的设置。这意味着 字符列表可以写成双引号字符串, 遵循 Marseille Prolog 的传统。

例如,以下查询成功:

?- "abc" = [a,b,c].
   true.

这表明字符串 "abc" 在内部表示为 3 字节的序列, 在 Prolog 程序中表现为字符列表。

Scryer Prolog 对部分字符串使用相同的编码方式, 这些字符串在 Prolog 代码中表现为部分字符列表。 来自 library(iso_ext) 的谓词 partial_string/3 允许您 显式地构造部分 字符串。例如:

?- partial_string("abc", Ls0, Ls).
   Ls0 = [a,b,c|Ls].

在这种情况下,正如答案所示,Ls0 与尾部为 Ls 的部分列表无法区分,而内部则使用高效的打包表示。

Scryer Prolog 的一个重要设计目标是尽可能自动使用高效的字符串表示。因此,几乎很少需要显式使用 partial_string/3。在上面的示例中,发布 Ls0 = [a,b,c|Ls] 会产生完全相同的内部表示,并且具有仅使用标准谓词 (=)/2 的优势。

字符串和部分字符串的高效内部表示最初由 Ulrich Neumerkel 在 issues #24 和 #95 中提出并解释, Scryer Prolog 是第一个实现它的 Prolog 系统。

发生检查和循环项

发生检查(occurs check)是执行语法统一算法的一个组成部分,如果变量与包含该变量作为真子项的项进行统一,则导致统一失败。出于效率考虑,Scryer Prolog 和许多其他 Prolog 系统默认省略发生检查(occurs check)。

在 Scryer Prolog 中,只有在省略发生检查(occurs check)时才能成功的统一会产生循环项(cyclic terms),也称为有理树(rational trees)。例如:

?- X = f(X), Y = g(X,Y).
   X = f(X), Y = g(f(X),Y).

循环项的创建通常表明 Prolog 谓词的定义中存在编程错误,为了获得逻辑上正确的结果,最好启用 occurs check 执行所有统一操作,或者在需要启用 occurs check 以防止统一时让 Prolog 抛出错误。

Scryer Prolog 通过 Prolog 标志 occurs_check 支持此功能。它可以设置为以下值之一以获得所需的行为:

  • false 不执行 occurs check。这是默认设置。
  • true 启用 occurs check 执行所有统一操作。
  • error 如果执行了 occurs check 本会阻止的统一操作,则返回错误。

特别是对于刚开始学习 Prolog 的用户,我们建议在 ~/.scryerrc 配置文件中添加以下指令,以便通过错误指示导致循环项创建的谓词中的编程错误:

:- set_prolog_flag(occurs_check, error).

Scryer Prolog 实现了专门的推理机制,即使在启用了 occurs check 的情况下,也能在许多常见场景中 使统一操作快速完成。

Tabling (SLG resolution)

Prolog 的一大主要吸引力在于,纯 程序的逻辑推论 可以通过多种执行策略推导得出,这些策略在终止性、 完备性和效率等关键特性上各不相同。

Prolog 的默认执行策略是带有时间回溯的深度优先搜索。该策略非常高效。其主要 缺点是它是不完备的:即使存在解,它也可能找不到任何解。

Scryer Prolog 支持一种替代执行策略,称为 tabling,也被称为 tabled execution 和 SLG resolution。要为某个谓词启用 tabled 执行,请使用 library(tabling) 并为所需的谓词指示符添加一个 (table)/1 指令。例如,如果我们 编写:

:- use_module(library(tabling)).
:- table a/0.

a :- a.

然后查询 ?- a. 终止(并失败),而在默认执行策略下它 不会 终止。

Scryer Prolog 通过 delimited continuations 实现 tabling, 如 Tabling as a Library with Delimited Control 中 Desouter et. al. 所述。

Constraint Logic Programming (CLP)

Scryer Prolog 为 Constraint Logic Programming (CLP) 提供了出色的支持,它是 Logic Programming (LP) 和 Constraints 的结合。

除了对 dif/2, freeze/2, CLP(B)CLP(ℤ) 的内置支持外, Scryer 提供了一种方便的方式来实现新的用户定义 约束:Attributed variables 可通过 library(atts) 使用,正如 SICStus Prolog 中那样, 这是现存最复杂且最快的约束系统之一。在 library(iso_ext) 中, Scryer 提供了用于可回溯(bb_b_put/2)和 不可回溯(bb_put/2)全局变量的谓词,这些是实现某些类型约束 求解器所必需的。

这些特性使 Scryer Prolog 成为教学、 学习和开发可移植 CLP 应用的理想平台。

Modules

Scryer 拥有一个简单的基于谓词的模块系统。它提供 一种将代码单元分离到不同命名空间的方式,适用于 谓词和运算符。参见文件 src/lib/*.pl 以 获取示例。

在撰写本文时,许多谓词位于各自的模块中, 在使用之前需要导入这些模块。 随 Scryer Prolog 一起提供的模块也被称为 library 模块或 libraries,包括:

  • lists 提供 length/2member/2select/3append/[2,3]foldl/[4,5]maplist/[2-9]same_length/2transpose/2 等。
  • dcgs 确定子句文法(DCGs),一种内置的语法机制, 使用运算符 (-->)/2 来定义语法规则, 并使用谓词 phrase/[2,3] 来调用它们。
  • dif 谓词 dif/2 提供声明式不等式: 当且仅当其参数不同时为真,并且 延迟测试直到可以做出可靠决策为止。
  • reif 提供 if_/3tfilter/3 及相关谓词, 如 Indexing dif/2 中所述。
  • clpz CLP(ℤ):整数约束逻辑编程, 通过 (#=)/2(#\=)/2(#>=)/2 等提供声明式整数算术,以及各种全局约束和 枚举谓词,用于求解组合任务。
  • pairs 按照惯例,pairs 是主 functor 为 (-)/2 的 Prolog 项, 写作 Key-Value。 本库提供 pairs_keys_values/3pairs_keys/2 以及其他谓词,用于对 pairs 进行推理。
  • si 谓词 atom_si/1integer_si/1atomic_si/1list_si/1 实现可靠的类型检查。如果无法做出决策,它们会引发 实例化错误。它们是逻辑上存在缺陷的 低级类型测试的声明式替代方案。例如,不要使用 integer(X), 而是编写 integer_si(X) 以确保程序的可靠性。 "si" 代表 sufficiently instantiated(充分实例化),也代表 sound inference(可靠推理)。
  • debug 各种允许声明式调试的谓词。
  • pio phrase_from_file/2 将 DCG 非终结符应用于文件内容, 仅按需惰性读取所需的部分。得益于紧凑的内部字符串表示, 即使非常大的文件也能通过 Scryer Prolog 以这种方式高效处理。 phrase_to_file/2phrase_to_stream/2 分别将 DCG 描述的字符列表写入文件和流。
  • lambda 用于简化高阶编程的 Lambda 表达式。
  • charsio 各种有用的谓词, 用于解析和推理字符,特别是 char_type/2 用于 根据类型对字符进行分类,以及针对不同字符串编码的转换 谓词。
  • error must_be/2can_be/2 补充了由 library(si) 提供的类型检查,对于 Prolog 库作者特别有用。
  • tabling 运算符 (table)/1 用于准备谓词以进行表驱动执行(SLG 归结)的指令中。
  • format 非终结符 format_//2 用于描述格式化输出, 根据给定的格式 字符串排列参数。 谓词 format/[2,3]portray_clause/[1,2]listing/1 提供格式化的不纯输出。
  • assoc 提供 empty_assoc/1get_assoc/3put_assoc/4 等, 用于管理 AVL 树中的元素,确保 O(log(N)) 访问。
  • ordsets 将有序集表示为列表。
  • clpb CLP(B):基于布尔变量的约束逻辑编程, 通过谓词 sat/1taut/2labeling/1 等提供的基于 BDD 的 SAT 求解器。
  • arithmetic 算术谓词,例如 lsb/2msb/2number_to_rational/2
  • time 用于推理 时间的谓词,包括用于测量目标 CPU 时间的 time/1、 用于获取当前系统时间的 current_time/1、用于描述包含日期和时间的字符串的非终结符 format_time//2,以及用于减慢计算速度的 sleep/1
  • files 用于推理文件和目录的谓词,例如 directory_files/2file_exists/1file_size/2
  • cont 通过 reset/3shift/1 提供定界续体
  • random 概率谓词和随机数生成器。
  • http/http_open 打开一个流, 用于从 web 服务器读取答案。也支持 HTTPS。
  • http/http_server 运行 HTTP/1.1 和 HTTP/2.0 web 服务器。使用 Warp 作为后端。支持一些查询和表单处理。
  • sgml load_html/3load_xml/3 将 HTML 和 XML 文档 表示为 Prolog 项,以便进行方便且高效的推理。使用 library(xpath) 从 解析后的文档中提取信息。
  • csv parse_csv//1parse_csv//2 可与 phrase_from_file/2phrase/2 一起用于解析 csv
  • serialization/abnf 描述 ABNF 语法核心 (RFC 5234) 的 DCG, 它用于描述许多 IETF 语法,例如 HTTP v1.1SMTPiCalendar 等。
  • serialization/json json_chars//1 可与 phrase_from_file/2phrase/2 一起用于解析和生成 JSON
  • xpath 谓词 xpath/3 用于方便地推理 HTML 以及 XML 文档,受 XPath 语言启发。该库 通常与 library(sgml) 一起使用。
  • sockets 用于打开和接受 TCP 连接作为流的谓词。
  • os 用于推理环境 变量的谓词。
  • iso_ext 符合 Prolog ISO 标准的扩展及候选纳入项,例如 setup_call_cleanup/3call_nth/2call_with_inference_limit/3
  • crypto 密码学安全的随机数和哈希,基于 HMAC 的密钥 派生 (HKDF),基于密码的密钥派生 (PBKDF2), 使用 Ed25519 的公钥签名和签名验证, 基于 Curve25519 的 ECDH 密钥 交换 (X25519),使用 ChaCha20-Poly1305 的认证对称 加密,以及关于椭圆曲线的推理。
  • process 创建和管理并行进程。
  • uuid UUIDv4 生成和十六进制表示
  • tls 用于显式协商 TLS 连接的谓词。
  • numerics/special_functions 用于 erf、gamma、beta 及相关特殊函数的谓词。
  • ugraphs 图操作库
  • simplex 提供 assignment/2transportation/4 以及其他用于求解线性 规划问题的谓词。

要使用 lists 库提供的谓词,请编写:

?- use_module(library(lists)).

要加载包含在文件中的模块,可以省略 library 函子, 这将提示 Scryer 从其工作目录中搜索该文件(以原子形式指定):

?- use_module('file.pl').

use_module 指令可以通过添加导入列表进行限定:

?- use_module(library(lists), [member/2]).

合格的 use_module 可以通过传入空的导入列表来移除 toplevel 中的导入。

(:)/2 运算符将可能未导入到当前工作命名空间的谓词调用解析为:

?- lists:member(X, Xs).

The [user] 提示也可用于在 REPL 中内联定义模块:

?- [user].
:- module(test, [local_member/2]).
:- use_module(library(lists)).

local_member(X, Xs) :- member(X, Xs).

用户列表也可以通过在流的末尾放置 end_of_file. 来终止。

配置文件

启动时,如果文件 ~/.scryerrc 存在,Scryer Prolog 会咨询该文件。此文件可用于自动加载库并定义您经常需要的谓词。

例如,~/.scryerrc 的一个合理起点是:

:- use_module(library(lists)).
:- use_module(library(dcgs)).
:- use_module(library(reif)).

开发环境

为了编写和编辑 Prolog 程序,我们推荐 GNU Emacs 配合 Prolog mode 由 Stefan Bruda 维护。

使用 ediprolog 来咨询 Prolog 代码并在任意 Emacs 缓冲区中评估 Prolog 查询。

显示 Prolog 项为树的 Emacs 定义 可在 tools 中获取。

为了调试 Prolog 代码,我们推荐来自 library(debug) 的谓词,特别是:

  • (*)/1 用于*"泛化掉"*一个 Prolog 目标。使用它来调试 意外的失败,通过泛化你的定义直到它们 成功。只需在目标前放置 * 即可将其泛化掉。
  • ($)/1 用于发出执行的跟踪,显示目标 何时被调用,以及何时成功。在目标前放置 $ 以发出该目标的相关信息。

这种调试 Prolog 代码的方式有几个主要优点,例如: 它贴近正在考虑的 Prolog 代码本身,它不需要 额外的工具和形式化方法即可应用,并且 此外,它鼓励声明式推理,这在原则上 也可以自动执行。

应用

Scryer Prolog 对 Prolog ISO 标准的坚定承诺使其 非常适合用于受严格监管的 企业和政府 机构 涉及互操作性、 标准 合规性和保修。

Scryer Prolog 的成功现有应用包括:

Scryer Prolog 也非常适合教授和学习 Prolog,以及测试现有 Prolog 程序的语法一致性,从而测试其可移植性。

Scryer Prolog 聚会

Scryer Prolog 聚会是一个绝佳的机会,用于展示和了解 Scryer Prolog 及其应用的最新发展,交流关于当前 计划和 未来 方向的思路,并面对面讨论项目和愿景。

支持与讨论

如果 Scryer Prolog 崩溃或产生意外错误,请考虑提交 一个 issue

要与 Scryer Prolog 社区联系,请参与 讨论 或访问我们在 Libera 上的 #scryer IRC 频道!