Visual Prolog 7 - PDC Download site
Visual Prolog 7 - PDC Download site
Visual Prolog 7 - PDC Download site
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Visual</strong> <strong>Prolog</strong> 7.2 语 言 参 考 手 册<br />
本 文 档 描 述 <strong>Visual</strong> <strong>Prolog</strong> 编 程 语 言 的 语 法 与 语 义 。<br />
<strong>Visual</strong> <strong>Prolog</strong> 是 面 向 对 象 的 强 类 型 编 程 语 言 , 它 的 基 础 是 逻 辑 编 程 语 言 <strong>Prolog</strong>。<br />
一 个 <strong>Visual</strong> <strong>Prolog</strong> 程 序 是 由 一 个 目 标 及 一 些 :<br />
• interfaces( 接 口 )<br />
• Class declarations( 类 声 明 ) 及<br />
• Class implementations( 类 实 现 )<br />
构 成 的 , 上 述 这 些 部 件 包 含 有 下 面 这 些 <strong>Prolog</strong> 实 体 的 声 明 与 定 义 :<br />
• Domains ( 域 )<br />
• Constants ( 常 数 )<br />
• Predicates ( 谓 词 )<br />
• Properties ( 属 性 )<br />
• Fact databases ( 事 实 数 据 库 )。<br />
<strong>Visual</strong> <strong>Prolog</strong> 的 实 际 代 码 是 clauses( 子 句 ), 它 在 类 实 现 当 中 , 谓 词 是 由 它 实 现 的 。<br />
基 本 概 念<br />
Types and Subtypes ( 类 型 和 子 类 型 )<br />
Types<br />
<strong>Visual</strong> <strong>Prolog</strong> 的 类 型 分 为 对 象 类 型 与 值 类 型 。 对 象 是 易 变 的 而 值 是 非 易 变 的 。<br />
对 象 的 类 型 是 由 interface( 接 口 ) 定 义 的 。<br />
值 的 类 型 包 括 numerical types( 数 值 类 型 )、strings( 串 )、character types( 字 符 类 型 ) 和 compound<br />
domains( 复 合 域 )。 复 合 域 又 称 为 代 数 数 据 类 型 , 它 的 简 单 形 式 有 结 构 及 枚 举 类 型 , 而 其 复 杂 形 式 会 呈<br />
现 为 树 的 结 构 。<br />
Subtypes<br />
类 型 是 由 子 类 型 体 系 构 成 的 。 子 类 型 用 来 引 入 多 态 包 容 性 : 任 何 期 望 某 类 型 值 的 语 境 也 能 很 好 地 接 受<br />
任 意 子 类 型 的 值 。 也 可 以 反 过 来 说 , 某 个 类 型 的 值 在 需 要 的 时 候 可 以 自 动 地 转 换 成 任 意 父 类 型 加 以 应 用 ,<br />
而 不 需 要 显 式 的 类 型 转 换 。<br />
子 类 型 可 以 由 除 代 数 数 据 类 型 而 外 的 任 何 值 类 型 派 生 出 来 。 代 数 数 据 类 型 派 生 出 的 类 型 是 异 名 类 型 而<br />
不 是 子 类 型 , 也 就 是 说 , 它 们 是 相 同 的 类 型 而 非 子 类 型 。<br />
子 类 型 和 子 集 在 概 念 上 很 相 近 , 但 是 一 定 要 注 意 , 即 便 一 个 类 型 “ 算 术 上 ” 是 另 一 个 类 型 的 子 集 它 也<br />
末 必 就 是 一 个 子 类 型 。 只 有 声 明 了 之 后 一 个 类 型 才 可 以 是 另 一 个 类 型 的 子 类 型 。<br />
domains<br />
t1 = [1..17].<br />
t2 = [5..13].<br />
t3 = t1 [5..13].<br />
1
t1 是 整 数 类 型 , 它 的 值 从 1 到 17( 含 )。 而 t2 的 值 是 5 到 13, 所 以 ,t2 是 t1 的 一 个 子 集 , 但 它<br />
并 非 t1 的 一 个 子 类 型 。 另 一 方 面 ,t3( 它 也 含 有 与 t2 一 样 的 值 ) 则 是 t1 的 一 个 子 类 型 , 因 为 声 明 如 此 。<br />
本 语 言 中 有 几 个 隐 含 的 子 类 型 关 系 , 但 一 般 而 言 子 类 型 关 系 都 必 须 在 类 型 定 义 中 显 式 地 说 明 。<br />
对 象 类 型 也 是 由 子 类 型 体 系 构 成 的 , 根 是 预 定 义 的 对 象 类 型 Object, 也 就 是 说 任 意 对 象 类 型 都 是<br />
Object 的 子 类 型 。 对 象 子 类 型 的 定 义 是 通 过 声 明 说 一 个 接 口 支 持 另 一 个 而 实 现 的 。 如 果 一 个 对 象 具 有 支<br />
持 某 个 其 它 接 口 的 接 口 / 对 象 , 那 么 该 对 象 就 有 了 那 个 类 型 , 可 以 无 冲 突 地 当 作 那 个 对 象 来 使 用 。<br />
参 看 :Universal and Root Types( 通 用 类 型 和 根 类 型 )<br />
对 象 系 统<br />
外 视 图<br />
这 一 节 的 描 述 不 是 对 类 的 一 般 性 的 介 绍 , 而 是 对 <strong>Visual</strong> <strong>Prolog</strong> 中 类 的 概 念 说 明 , 希 望 读 者 已 经 熟 悉<br />
通 常 的 类 概 念 。 描 述 完 全 是 纯 概 念 意 义 上 的 , 不 涉 及 语 法 、 实 现 等 , 也 不 考 虑 操 作 或 编 程 方 面 的 问 题 。 尽<br />
管 引 入 类 、 对 象 的 主 要 原 因 是 程 序 本 质 上 的 要 求 , 但 只 描 述 基 本 观 念 而 不 去 考 虑 程 序 上 的 原 因 还 是 很 有 价<br />
值 的 。<br />
<strong>Visual</strong> <strong>Prolog</strong> 中 类 的 概 念 是 以 如 下 三 个 语 义 实 体 为 基 础 的 :<br />
• objects<br />
• interfaces<br />
• classes<br />
Object<br />
一 个 对 象 , 就 是 一 套 命 名 了 的 对 象 成 员 谓 词 及 一 套 支 持 的 接 口 。<br />
其 实 对 象 也 有 状 态 , 但 这 个 状 态 只 能 通 过 成 员 谓 词 才 能 改 变 和 观 察 。 我 们 称 之 为 状 态 封 装 在 对 象 中 。<br />
这 里 的 封 装 , 意 味 着 对 象 有 隐 藏 其 内 部 数 据 和 方 法 的 能 力 , 使 对 对 象 的 访 问 受 控 。 封 装 和 模 块 化 的 重<br />
要 性 是 众 所 周 知 的 。 封 装 有 助 于 构 建 更 加 结 构 化 和 易 读 的 程 序 , 因 为 对 象 可 以 看 作 为 一 个 黑 盒 子 。 要 解 一<br />
个 复 杂 的 问 题 , 先 找 出 可 以 下 断 言 和 描 述 的 一 部 分 , 把 它 封 装 在 一 个 对 象 里 , 构 造 一 个 接 口 , 接 着 再 往 下 ,<br />
直 到 声 明 了 所 有 子 问 题 。 封 装 了 问 题 对 象 后 , 只 要 保 证 它 们 工 作 正 常 , 就 可 以 从 对 象 中 抽 取 数 据 。<br />
Interface<br />
接 口 是 一 个 对 象 类 型 , 它 有 一 个 名 字 并 定 义 一 组 命 名 了 的 对 象 谓 词 。<br />
接 口 按 支 持 体 系 构 建 ( 这 个 结 构 是 半 格 状 的 , 根 是 interface 对 象 )。 如 果 一 个 对 象 具 有 一 个 接 口 表 示<br />
的 类 型 , 它 也 就 有 所 有 支 持 接 口 的 类 型 。 因 此 , 支 持 体 系 也 是 类 型 体 系 。 一 个 接 口 是 所 有 它 支 持 的 接 口 的<br />
一 个 子 类 型 。 也 可 以 说 对 象 支 持 接 口 , 如 果 接 口 名 为 X, 我 们 可 以 说 这 个 对 象 是 一 个 X, 或 是 一 个 X 对 象 。<br />
Class<br />
类 是 命 名 了 的 对 象 工 厂 , 它 创 建 相 应 于 某 个 接 口 的 对 象 。 任 何 对 象 都 是 由 类 创 建 的 , 如 果 一 个 类 是 用<br />
接 口 C 构 造 对 象 的 , 那 么 这 个 类 创 建 的 所 有 对 象 都 叫 C 对 象 。<br />
由 某 个 类 构 造 的 所 有 对 象 共 享 相 同 的 对 象 成 员 谓 词 定 义 , 但 每 个 对 象 有 其 自 己 的 状 态 。 因 此 , 对 象 成<br />
员 谓 词 实 际 上 是 类 的 一 部 分 , 而 对 象 的 状 态 则 是 对 象 本 身 的 一 部 分 。<br />
2
类 还 含 有 被 称 为 类 成 员 和 类 状 态 的 另 一 组 命 名 了 的 谓 词 和 封 装 的 状 态 。 类 成 员 与 类 状 态 存 在 于 各 个 类<br />
中 , 而 对 象 成 员 与 对 象 状 态 存 在 于 各 个 对 象 中 。 类 成 员 和 对 象 成 员 都 可 以 访 问 类 状 态 。<br />
注 意 ! 一 个 类 所 定 义 的 对 象 成 员 谓 词 组 是 在 该 类 的 接 口 中 声 明 的 谓 词 联 合 体 , 更 明 确 地 说 , 如 果 在 不<br />
同 的 两 个 接 口 中 声 明 了 同 一 个 谓 词 , 类 只 会 提 供 该 谓 词 的 一 个 定 义 。 因 此 , 类 只 是 检 测 实 际 意 义 , 也 就 是<br />
说 只 是 看 这 两 个 继 承 谓 词 的 预 期 语 义 是 否 一 致 。<br />
要 注 意 , 接 口 支 持 必 须 明 确 地 指 定 。 某 个 类 提 供 相 应 某 个 接 口 的 谓 词 并 不 意 味 着 这 个 类 支 持 这 个 接 口 。<br />
Module( 模 块 )<br />
事 实 上 , 类 不 必 非 得 能 产 生 对 象 。 不 产 生 对 象 的 类 只 有 类 成 员 和 类 状 态 , 而 这 样 的 类 当 模 块 看 待 更 恰<br />
当 。<br />
Identity( 标 识 )<br />
每 个 对 象 都 是 唯 一 的 : 对 象 具 有 可 变 的 状 态 , 而 且 对 象 的 状 态 只 能 通 过 它 们 的 成 员 谓 词 观 察 到 , 因 而<br />
对 象 只 与 它 自 己 是 同 一 的 。 这 就 是 说 , 即 使 有 两 个 对 象 的 状 态 是 一 样 的 , 它 们 也 不 是 同 一 的 , 因 为 我 们 可<br />
以 改 变 一 个 对 象 的 状 态 而 不 影 响 另 一 个 对 象 的 状 态 。<br />
我 们 无 法 直 接 访 问 一 个 对 象 的 状 态 , 而 总 是 通 过 对 象 的 引 用 来 访 问 对 象 的 状 态 。 尽 管 对 象 仅 与 自 身 是<br />
同 一 的 , 但 可 以 有 许 多 对 同 一 对 象 的 引 用 。 因 此 , 一 个 对 象 可 以 由 许 多 不 同 的 引 用 来 访 问 。<br />
类 和 接 口 也 是 唯 一 的 , 用 它 们 的 名 字 来 标 识 。 在 一 个 程 序 中 , 两 个 接 口 或 两 个 类 不 能 用 相 同 的 名 字 ,<br />
只 有 当 一 个 类 构 造 一 个 接 口 的 对 象 时 , 这 一 个 类 和 这 一 个 接 口 才 可 以 用 相 同 的 名 字 。<br />
总 之 , 结 构 的 相 同 并 不 意 味 着 同 一 , 对 对 象 、 类 和 接 口 都 是 这 样 的 。<br />
内 视 图<br />
前 一 节 描 述 了 对 象 、 类 及 接 口 的 外 在 表 现 , 这 一 节 描 述 内 部 情 况 。 这 些 内 部 问 题 更 具 程 序 特 性 , 可 以<br />
把 它 们 分 成 声 明 与 实 现 两 个 部 分 来 考 虑 。<br />
从 程 序 的 观 点 , 类 是 核 心 : 代 码 是 包 含 在 类 中 的 。<br />
接 口 主 要 地 是 静 态 特 性 , 实 事 上 , 接 口 只 存 在 于 一 个 程 序 的 文 本 表 示 中 , 运 行 时 没 有 一 个 ( 直 接 的 )<br />
代 表 接 口 的 东 西 。 而 另 一 方 面 , 对 象 主 要 地 是 动 态 特 性 , 它 在 程 序 中 并 不 是 直 接 可 见 的 , 直 到 程 序 实 际 运<br />
行 时 它 才 存 在 。<br />
类 由 声 明 与 实 现 构 成 。 声 明 通 告 了 类 的 public( 公 共 ) 可 访 问 的 部 分 及 它 生 成 的 对 象 。 而 实 现 则 defines<br />
( 定 义 ) 在 类 声 明 中 声 明 了 的 实 体 。 谓 词 的 基 本 实 现 当 然 是 子 句 , 但 谓 词 也 可 以 由 继 承 定 义 , 或 是 由 外<br />
部 的 库 来 确 定 。<br />
在 <strong>Visual</strong> <strong>Prolog</strong> 中 , 类 的 声 明 纯 粹 是 说 明 , 它 只 是 陈 述 有 哪 些 实 体 可 以 访 问 , 但 并 不 涉 及 如 何 访 问 及<br />
实 体 在 哪 儿 实 现 。<br />
类 实 现 可 以 声 明 和 定 义 更 多 的 实 体 ( 域 、 谓 词 等 ), 它 们 只 在 类 的 内 部 是 可 见 的 , 也 就 是 说 , 它 们 是<br />
私 有 的 (private)。<br />
对 象 的 状 态 是 存 储 在 对 象 本 身 的 事 实 中 的 , 这 些 事 实 是 在 类 的 实 现 中 普 通 事 实 ( 数 据 库 ) 段 中 声 明 的 。<br />
事 实 对 每 个 对 象 都 是 局 部 的 ( 就 像 其 它 的 对 象 实 体 ), 而 类 事 实 则 由 同 类 的 所 有 对 象 共 享 。<br />
事 实 只 能 在 类 的 实 现 中 声 明 , 因 而 也 就 不 能 从 类 的 外 部 ( 直 接 ) 访 问 。<br />
类 的 实 现 也 可 以 声 明 它 支 持 除 类 声 明 中 提 到 的 以 外 的 其 它 接 口 。 但 这 个 消 息 也 仅 只 在 实 现 本 身 内 部 是<br />
可 见 的 , 因 而 还 是 私 有 的 。<br />
3
代 码 继 承<br />
<strong>Visual</strong> <strong>Prolog</strong> 的 代 码 继 承 只 能 在 类 的 实 现 中 进 行 , 可 以 有 多 重 继 承 。 通 过 在 类 实 现 中 特 殊 的 inherits<br />
段 标 记 一 个 类 来 得 到 该 类 的 继 承 。 被 继 承 的 类 称 为 父 类 (parent classes) 或 超 类 (super-classes), 子<br />
类 (Child class) 或 亚 类 (sub-class) 与 父 类 是 成 对 的 , 我 们 也 说 子 类 继 承 自 父 类 。 子 类 只 能 通 过 父 类<br />
的 公 共 接 口 访 问 它 的 父 类 , 也 就 是 说 它 与 其 它 使 用 该 父 类 的 类 一 样 , 并 没 有 接 受 额 外 的 特 权 。<br />
Scoping & Visibility( 范 围 与 可 见 性 )<br />
名 称 类 别<br />
<strong>Visual</strong> <strong>Prolog</strong> 中 的 所 有 名 称 ( 标 识 ) 按 语 法 分 成 两 个 大 组 :<br />
• 常 量 名 称 ( 以 小 写 字 母 开 头 )<br />
• 变 量 名 称 ( 以 大 字 字 母 或 下 划 线 开 头 )<br />
常 量 名 称 又 分 为 如 下 几 类 :<br />
• 类 型 名 ( 如 域 和 接 口 );<br />
• 域 载 体 ( 如 类 和 接 口 );<br />
• 不 带 圆 括 号 的 名 称 ( 如 常 数 、 非 函 数 类 型 的 事 实 变 量 及 零 函 子 );<br />
• 返 回 值 的 元 维 为 N 的 名 称 ( 如 函 数 、 函 子 和 函 数 类 型 的 事 实 变 量 );<br />
• 不 返 回 值 的 元 维 为 N 的 名 称 ( 如 谓 词 、 事 实 及 谓 词 类 型 的 事 实 变 量 )。<br />
<strong>Visual</strong> <strong>Prolog</strong> 要 求 在 声 明 阶 段 名 称 就 不 能 有 冲 突 , 因 为 在 使 用 阶 段 它 就 不 可 能 解 决 这 样 的 冲 突 了 。 只<br />
有 在 同 一 范 围 的 名 称 才 可 能 会 有 冲 突 , 而 不 同 的 范 围 因 为 范 围 的 限 定 可 以 解 决 冲 突 。 某 个 类 别 的 名 称 决 不<br />
会 与 另 一 个 类 别 中 的 名 称 有 冲 突 , 但 是 我 们 就 要 看 到 在 单 个 声 明 中 可 以 把 一 个 名 字 放 在 几 个 类 别 中 。<br />
Packages( 包 )<br />
包 , 是 <strong>Visual</strong> <strong>Prolog</strong> 中 一 般 公 认 的 代 码 组 织 基 本 单 位 , 我 们 用 包 来 组 建 东 西 。 包 的 使 用 , 保 证 了 不 同<br />
工 程 间 构 造 原 则 的 一 致 性 。 包 为 工 程 间 构 造 和 共 享 代 码 的 工 具 确 定 了 标 准 。<br />
包 是 成 组 的 接 口 和 类 的 集 合 体 , 它 为 所 有 这 些 接 口 和 类 提 供 了 某 个 共 同 的 名 称 。 包 里 每 个 接 口 的 各 个<br />
声 明 或 实 现 是 放 在 独 立 的 文 件 中 的 , 这 些 文 件 的 文 件 名 与 在 该 文 件 中 声 明 的 或 实 现 的 类 或 接 口 的 名 称 相 对<br />
应 。 所 有 包 文 件 存 放 在 一 个 独 立 的 包 目 录 下 ( 如 果 一 个 包 有 子 包 , 则 子 包 会 放 在 包 目 录 的 子 目 录 中 )。<br />
包 的 概 念 , 用 来 把 一 些 相 关 的 接 口 与 类 组 合 在 一 起 , 它 起 了 一 个 类 库 角 色 的 作 用 。 在 程 序 中 包 可 以 把<br />
使 用 的 接 口 和 类 集 中 起 来 , 而 不 是 直 接 把 这 些 接 口 和 类 放 在 程 序 里 。<br />
在 帮 助 文 件 中 的 VDE 部 分 , 描 述 了 <strong>Visual</strong> <strong>Prolog</strong> 中 可 用 的 包 结 构 及 如 何 将 包 放 到 工 程 中 。( 参 看<br />
Creating a Package in Creating New Project Items)<br />
可 见 性 、 屏 蔽 及 限 定 符<br />
大 多 数 范 围 规 则 上 面 都 说 了 , 这 一 节 最 后 完 善 整 个 内 容 。<br />
接 口 定 义 , 类 声 明 以 及 类 实 现 都 是 范 围 ( 范 围 不 能 嵌 套 )。 实 现 ( 悄 悄 地 ) 扩 展 了 相 应 的 类 声 明 的 范<br />
围 。 在 一 个 范 围 内 , 可 见 性 到 处 都 是 一 样 的 。 这 尤 其 是 指 在 一 个 范 围 内 不 论 某 个 东 西 是 在 哪 儿 声 明 的 , 它<br />
在 整 个 范 围 内 都 是 可 见 的 。<br />
来 自 被 支 持 的 接 口 和 超 类 的 公 用 名 称 , 如 果 它 出 自 何 处 不 模 糊 , 在 一 个 范 围 内 是 直 接 可 用 的 ( 也 就 是<br />
不 需 要 限 定 符 )。 谓 词 调 用 中 的 模 糊 问 题 , 可 以 用 带 类 名 的 谓 词 名 的 修 饰 方 法 ( 如 cc::p) 来 解 决 。<br />
4
这 样 的 限 定 符 , 也 用 于 修 饰 当 前 对 象 对 超 类 的 对 象 成 员 谓 词 的 调 用 中 。<br />
<strong>Visual</strong> <strong>Prolog</strong> 有 两 个 屏 蔽 层 级 :<br />
• 局 部 的<br />
• 超 类 及 开 放 范 围 (opened scopes)<br />
开 放 范 围 的 情 况 与 超 类 的 一 样 , 所 以 我 们 下 面 只 说 超 类 。<br />
层 级 的 意 思 是 , 局 部 声 明 会 屏 蔽 超 类 声 明 , 但 两 个 超 类 间 不 会 有 屏 蔽 , 所 有 超 类 都 有 同 样 的 优 选 权 。<br />
如 果 两 个 或 更 多 个 超 类 包 含 有 冲 突 的 声 明 , 那 这 些 声 明 就 只 能 通 过 限 定 符 来 访 问 。<br />
例 设 有 接 口 aa 及 类 aa_class:<br />
interface aa<br />
predicates<br />
p1 : () procedure ().<br />
p2 : () procedure ().<br />
p3 : () procedure ().<br />
end interface<br />
class aa_class : aa<br />
end class<br />
再 假 设 有 bb_class 类 :<br />
class bb_class<br />
predicates<br />
p3 : () procedure ().<br />
p4 : () procedure ().<br />
end class bb_class<br />
在 上 述 情 况 下 , 来 看 看 类 cc_class 的 实 现 :<br />
implement cc_class inherits aa_class<br />
open bb_class<br />
predicates<br />
p2 : () procedure ().<br />
p5 : () procedure ().<br />
clauses<br />
new() :-<br />
p1(),<br />
% aa_class::p1<br />
p2(),<br />
% cc::p2 ( 屏 蔽 了 aa_class::p2)<br />
aa_class::p2(), % aa_class::p2<br />
p3(),<br />
% 错 误 的 模 糊 调 用 : 可 以 是 aa_class::p3 或 bb_class::p3<br />
aa_class::p3(), % aa_class::p3<br />
bb_class::p3(), % bb_class::p3<br />
p4(),<br />
% bb_class::p4<br />
p5(),<br />
% cc::p5<br />
end implement cc_class<br />
词 汇 元 素<br />
源 文 件 要 经 过 <strong>Visual</strong> <strong>Prolog</strong> 编 译 器 的 编 译 。 一 个 源 文 件 可 以 包 含 其 它 的 源 文 件 , 从 概 念 上 来 讲 插 入 的<br />
这 些 文 件 与 包 含 它 们 的 文 件 组 成 了 一 个 编 译 单 元 。 一 个 编 译 单 元 的 编 译 要 经 过 两 个 概 念 上 的 步 骤 :<br />
• 首 先 , 输 入 被 转 换 成 记 号 的 序 列 ;<br />
5
• 其 次 , 对 这 些 记 号 进 行 语 法 分 析 并 转 换 成 可 执 行 代 码 。<br />
对 程 序 的 词 汇 分 析 把 编 译 单 元 CompilationUnit 再 细 分 成 输 入 元 素 InputElement 的 表 :<br />
CompilationUnit:<br />
InputElement-list<br />
InputElement:<br />
Comment<br />
WhiteSpace<br />
Token<br />
只 有 记 号 (Token) 对 后 面 的 语 法 分 析 有 意 义 。<br />
注 释<br />
<strong>Visual</strong> <strong>Prolog</strong> 的 注 释 可 以 按 以 下 方 法 编 写 :<br />
• 以 /*( 斜 杠 , 星 ) 开 头 , 后 面 是 任 意 字 符 序 列 ( 包 括 换 行 符 ), 结 束 用 */( 星 , 斜 杠 )。 这 样 的 注<br />
释 可 以 有 多 行 , 可 以 嵌 套 。<br />
• 以 %( 百 分 号 ) 开 头 , 后 面 是 任 意 字 符 序 列 。 这 样 的 注 释 在 一 行 的 结 尾 就 结 束 了 , 因 此 通 常 称 之<br />
为 单 行 注 释 。<br />
看 一 下 下 面 的 注 释 :<br />
/* 注 释 1 的 开 头<br />
% 嵌 套 了 注 释 2 */ 这 个 标 记 不 会 结 束 多 行 注 释<br />
因 为 它 插 入 了 一 个 单 行 注 释<br />
这 个 才 是 注 释 1 实 际 结 束 的 标 记 */<br />
空 白<br />
WhiteSpace:<br />
Space<br />
Tab<br />
NewLine<br />
这 里 的 Space 是 空 格 字 符 ,Tab 是 制 表 字 符 而 NewLine 是 换 行 字 符 。<br />
Tokens( 记 号 )<br />
Token:<br />
Identifier( 标 识 )<br />
Keyword( 关 键 字 )<br />
Punctuator( 标 点 )<br />
Operator( 操 作 符 )<br />
Literal( 文 字 )<br />
标 识<br />
Identifier:<br />
LowercaseIdentifier( 小 写 标 识 )<br />
UppercaseIdentifier( 大 写 标 识 )<br />
AnonymousIdentifier( 匿 名 标 识 )<br />
6
Ellipsis( 省 略 号 )<br />
小 写 标 识 是 一 个 以 小 写 字 母 开 头 的 字 母 、 数 字 及 下 划 线 组 成 的 序 列 ; 大 写 标 识 是 一 个 以 大 写 字 母 或 下<br />
划 线 开 头 的 字 母 、 数 字 及 下 划 线 组 成 的 序 列 。 匿 名 标 识 是 一 个 下 划 线 :“_”; 而 省 略 号 则 是 三 个 句 点 :“…”。<br />
关 键 字<br />
关 键 字 分 为 主 关 键 字 和 次 关 键 字 两 类 , 但 这 只 是 表 面 上 的 分 法 , 主 次 关 键 字 并 没 有 形 式 上 的 差 异 。 不<br />
过 我 们 下 面 还 是 用 不 同 颜 色 区 分 它 们 :<br />
Keyword :<br />
MajorKeyword( 主 关 键 字 )<br />
MinorKeyword( 次 关 键 字 )<br />
MajorKeyword : one of<br />
class clauses constants constructors<br />
delegate domains<br />
end<br />
facts<br />
goal guards<br />
implement inherits interface<br />
monitor<br />
namespace<br />
open<br />
predicates<br />
properties<br />
resolve<br />
supports<br />
MinorKeyword : one of<br />
align and anyflow as<br />
bitsize<br />
catch<br />
determ digits div do<br />
else elseif erroneous externally<br />
failure finally foreach from<br />
if<br />
language<br />
mod multi<br />
nondeterm<br />
or<br />
procedure<br />
quot<br />
rem<br />
single<br />
then to try<br />
所 有 关 键 字 除 了 as 和 language 都 是 保 留 字 。<br />
注 意 ,div 和 mod 也 是 保 留 字 , 但 它 们 是 归 类 在 操 作 符 中 的 。<br />
guards 和 monitor 在 语 言 中 并 没 有 使 用 , 但 它 们 是 保 留 给 将 来 使 用 的 。<br />
标 点 符 号<br />
7
标 点 符 号 在 <strong>Visual</strong> <strong>Prolog</strong> 中 对 编 译 器 既 有 语 法 意 义 又 有 语 义 意 义 , 但 它 们 本 身 不 是 能 产 生 值 的 操 作 运<br />
算 。 有 的 标 点 符 号 , 单 独 或 组 合 起 来 也 可 以 是 <strong>Visual</strong> <strong>Prolog</strong> 的 操 作 符 。<br />
操 作 符<br />
标 点 符 号 有 :<br />
PunctuationMarks: one of<br />
; ! , . # [ ] | ( ) :- : ::<br />
操 作 符 规 定 了 对 相 关 的 操 作 数 要 进 行 的 运 算 操 作 。<br />
Operators: one of<br />
+ - / * ^ = div mod quot rem<br />
< > >< = :=<br />
所 有 操 作 符 都 是 二 元 的 , 但 - 和 + 也 可 以 是 一 元 的 操 作 符 。<br />
div 和 mod 是 保 留 字 。<br />
文 字<br />
整 数 文 字<br />
文 字 概 括 了 下 面 的 内 容 : 整 数 、 字 符 、 浮 点 数 、 串 、 二 进 制 数 字 串 和 表 :<br />
Literal:<br />
IntegerLiteral<br />
RealLiteral<br />
CharacterLiteral<br />
StringLiteral<br />
BinaryLiteral<br />
ListLiteral<br />
CompoundDomainLiteral<br />
IntegerLiteral:<br />
UnaryPlus-opt DecimalDigit-list<br />
UnaryMinus-opt DecimalDigit-list<br />
UnaryPlus-opt OctalPrefix OctalDigit-list<br />
UnaryMinus-opt OctalPrefix OctalDigit-list<br />
UnaryPlus-opt HexadecimalPrefix HexadecimalDigit-list<br />
UnaryMinus-opt HexadecimalPrefix HexadecimalDigit-list<br />
UnaryPlus:<br />
+<br />
UnaryMinus:<br />
-<br />
OctalPrefix:<br />
0o<br />
OctalDigit: one of<br />
0 1 2 3 4 5 6 7<br />
DecimalDigit: one of<br />
0 1 2 3 4 5 6 7 8 9<br />
HexadecimalPrefix:<br />
0x<br />
8
HexadecimalDigit: one of<br />
0 1 2 3 4 5 6 7 8 9 A a B b C c D d E e F f<br />
一 个 整 数 文 字 可 以 属 于 整 数 或 无 符 号 数 域 , 它 不 能 超 过 整 数 或 无 符 号 数 的 最 大 和 最 小 值 。<br />
实 数 文 字<br />
RealLiteral:<br />
UnaryMinus-opt DecimalDigit-list FractionOfFloat-opt Exponent-opt<br />
FractionOfFloat:<br />
. DecimalDigit-list<br />
Exponent:<br />
ExponentSymbol ExponentSign-opt DecimalDigit-list<br />
ExponentSymbol: one of<br />
e E<br />
ExponentSign: one of<br />
- +<br />
浮 点 数 文 字 表 示 的 值 也 应 该 不 要 超 过 实 数 所 能 表 示 的 最 大 最 小 值 。<br />
字 符 文 字<br />
CharacterLiteral:<br />
' CharacterValue '<br />
上 面 的 CharacterValue 可 以 是 任 意 可 打 印 字 符 或 一 个 换 码 序 列 :<br />
• \\ 代 表 \<br />
• \t 代 表 制 表 符<br />
• \n 代 表 换 行 符<br />
• \r 代 表 回 车<br />
• \' 表 单 引 号<br />
• \" 代 表 双 引 号<br />
• \uXXXX, 这 里 的 XXXX 应 该 是 四 位 十 六 进 制 数 ,\uXXXX 代 表 相 应 这 个 数 的 Unicode 字 符 。<br />
串 文 字<br />
StringLiteral:<br />
StringLiteralPart-list<br />
StringLiteralPart:<br />
@" AnyCharacter-list-opt "<br />
" CharacterValue-list-opt "<br />
串 文 字 是 由 一 个 或 多 个 StringLiteralPart( 串 文 字 部 件 ) 连 接 构 成 的 。<br />
以 @ 开 头 的 串 文 字 部 件 不 使 用 换 码 序 列 , 除 了 下 述 情 况 :<br />
• "" 代 表 双 引 号 。<br />
而 不 用 @ 开 头 的 串 文 字 部 件 使 用 下 述 换 码 序 列 :<br />
• \\ 代 表 \<br />
• \t 代 表 制 表 符<br />
• \n 代 表 换 行 符<br />
9
• \r 代 表 回 车<br />
• \" 代 表 双 引 号<br />
• \uXXXX, 这 里 的 XXXX 应 该 是 四 位 十 六 进 制 数 , 代 表 相 应 这 个 数 的 Unicode 字 符 。<br />
二 进 制 数 文 字<br />
255。<br />
BinaryLiteral:<br />
$[ ElementValue-comma-sep-list-opt ]<br />
ElementValue:<br />
IntegerLiteral<br />
ElementValue 可 以 是 任 意 整 数 算 术 表 达 式 ( 如 常 数 ), 在 编 译 时 应 该 是 可 计 算 的 , 值 的 范 围 是 0 到<br />
表 文 字<br />
一 个 表 中 的 所 有 元 素 必 须 属 于 同 一 个 域 ( 或 兼 容 域 )。 域 可 以 是 任 何 内 建 (built-in) 的 或 用 户 定 义 域<br />
(user defined domain), 例 如 , 可 以 是 整 数 、 字 符 、 二 进 制 、 复 合 域 等 等 。<br />
ListLiteral:<br />
[ SimpleLiteral-comma-sep-list-opt ]<br />
[ SimpleLiteral-comma-sep-list | ListLiteral ]<br />
这 里 的 SimpleLiteral( 简 单 文 字 ) 可 以 是 :<br />
例 :<br />
复 合 域 文 字<br />
SimpleLiteral:<br />
IntegerLiteral<br />
RealLiteral<br />
CharacterLiteral<br />
StringLiteral<br />
BinaryLiteral<br />
ListLiteral<br />
CompoundDomainLiteral<br />
[] % 空 表<br />
[1,2,3] % 整 数 表<br />
["abc", "defg"] % 串 表<br />
[1,"abc"]<br />
% 这 个 表 不 合 规 定<br />
用 户 定 义 复 合 域 所 有 的 参 数 如 果 都 是 文 字 的 则 也 可 以 当 文 字 看 待 。<br />
编 译 单 元<br />
一 个 程 序 由 若 干 编 译 单 元 构 成 , 编 译 器 对 每 个 编 译 单 元 分 别 进 行 编 译 , 一 个 编 译 结 果 就 是 一 个 目 标 文<br />
件 。 这 些 目 标 文 件 ( 可 能 还 有 其 它 文 件 ) 链 接 在 一 起 , 就 产 生 了 工 程 的 结 果 。 一 个 程 序 必 须 有 一 个 、 也 只<br />
10
能 有 一 个 目 标 段 (goalSection), 它 是 整 个 程 序 的 入 口 。<br />
一 个 编 译 单 元 所 有 的 引 用 名 必 须 是 已 经 在 本 单 元 中 声 明 或 定 义 过 的 , 在 这 个 意 义 上 说 一 个 编 译 单 元 必<br />
须 是 独 立 的 。 接 口 定 义 与 类 声 明 可 以 包 含 在 数 个 编 译 单 元 中 ( 定 义 / 声 明 在 其 所 在 的 包 含 单 元 中 必 须 是 一 致<br />
的 ), 而 类 实 现 ( 定 义 ) 只 能 定 义 在 单 一 的 单 元 中 。 工 程 中 也 必 须 定 义 每 个 声 明 项 , 但 有 些 定 义 也 可 以 在<br />
库 中 , 也 就 是 说 不 一 定 非 要 原 文 定 义 。<br />
一 个 编 译 单 元 ( 其 中 可 能 含 有 #include 指 令 ) 是 一 个 编 译 项 的 序 列 。<br />
CompilationUnit :<br />
CompilationItem-list-opt<br />
一 个 编 译 项 可 以 是 一 个 接 口 、 一 个 类 声 明 、 一 个 类 实 现 、 目 标 段 或 是 一 个 条 件 编 译 项 ( 这 个 要 在 条 件<br />
编 译 中 介 绍 )。<br />
CompilationItem :<br />
Directive<br />
NamespaceEntrance<br />
ConditionalItem<br />
InterfaceDefinition<br />
ClassDeclaration<br />
ClassImplementation<br />
GoalSection<br />
请 参 看 :<br />
• Interfaces 接 口<br />
• Classes 类<br />
• Implementations 实 现<br />
• Namespace Entrances 名 称 空 间 入 口<br />
• Goal Section 目 标 段<br />
• Directives 指 令<br />
• Conditional Item 条 件 项<br />
Interfaces( 接 口 )<br />
一 个 接 口 定 义 规 定 了 一 个 已 经 命 名 对 象 的 类 型 。 接 口 可 以 支 持 其 它 的 接 口 , 详 细 内 容 请 参 看 Supports<br />
限 定 符 。<br />
在 一 个 接 口 中 声 明 的 所 有 谓 词 , 都 是 该 接 口 类 型 对 象 中 的 对 象 成 员 。 接 口 也 是 一 个 可 以 定 义 常 数 和 域<br />
的 全 局 范 围 , 因 此 , 在 一 个 接 口 中 定 义 的 常 数 和 域 , 并 不 是 该 接 口 ( 或 其 对 象 具 有 的 ) 类 型 的 部 件 。<br />
上 述 这 样 的 域 和 常 数 可 以 用 该 接 口 名 限 定 符 interface::constant, 或 是 使 用 open 限 定 符 ( 参 看<br />
Open 限 定 符 ) 在 其 它 范 围 中 引 用<br />
InterfaceDeclaration :<br />
interface IinterfaceName ScopeQualifications Sections end interface<br />
IinterfaceName-opt<br />
InterfaceName :<br />
LowerCaseIdentifier<br />
在 上 述 结 构 中 , 结 尾 处 的 接 口 名 (InterfaceName) 要 是 用 的 话 , 一 定 要 和 结 构 开 始 处 的 相 一 致 。<br />
11
ScopeQualifications 的 类 型 必 须 是 :<br />
• Supports 限 定 符<br />
• Open 限 定 符<br />
Sections 的 类 型 必 须 是 :<br />
• ConstantsSection 常 数 段<br />
• DomainsSection 域 段<br />
• PredicatesSection 谓 词 段<br />
• PredicatesFromInterface 来 自 接 口 的 谓 词<br />
• ConditionalSection 条 件 段<br />
在 条 件 段 中 包 含 的 所 有 段 也 必 须 是 这 些 类 型 的 。<br />
The interface: object( 接 口 : 对 象 )<br />
如 果 一 个 接 口 没 有 显 式 地 支 持 任 何 接 口 , 它 意 味 着 支 持 的 只 有 内 建 接 口 object。<br />
object 是 一 个 空 接 口 , 也 就 是 说 , 它 不 含 有 谓 词 等 。 它 的 主 要 用 途 是 作 为 所 有 对 象 的 一 个 通 用 的 基 础<br />
类 型 。<br />
Open 限 定 符<br />
Open 限 定 符 用 来 使 对 类 级 实 体 的 引 用 更 方 便 。Open 段 使 一 个 范 围 内 的 名 称 进 入 到 另 一 个 范 围 , 因 而<br />
可 以 不 用 限 定 符 地 加 以 引 用 。<br />
Open 对 对 象 成 员 的 名 称 没 有 影 响 , 因 为 它 们 只 能 通 过 对 象 来 访 问 。 但 是 对 类 成 员 、 域 、 函 子 及 常 数<br />
的 名 称 , 可 以 不 加 限 定 符 地 访 问 。<br />
用 这 样 的 方 式 把 名 称 带 入 到 一 个 范 围 时 , 可 能 会 引 起 一 些 名 称 的 混 淆 ( 参 看 Scoping)。<br />
Open 段 只 在 它 们 出 现 的 范 围 内 有 影 响 , 这 尤 其 是 指 在 一 个 类 声 明 中 的 open 段 不 会 影 响 到 类 的 实 现 。<br />
Supports 限 定 符<br />
OpenQualification :<br />
open ScopeName-comma-sep-list<br />
Supports 限 定 符 只 能 用 在 接 口 定 义 (interfaceDefinition) 与 类 实 现 (classImplementation) 中 。<br />
它 有 两 个 作 用 :<br />
• 指 定 用 一 个 接 口 A 扩 展 另 一 个 接 口 B, 因 而 使 A 类 型 的 对 象 是 B 类 型 对 象 的 一 个 子 类<br />
• 声 明 某 个 类 的 对 象 相 对 于 原 来 构 造 类 型 规 定 的 来 说 ,“ 私 下 地 ” 有 了 更 多 的 对 象 类 型<br />
supports 是 可 传 递 的 : 如 果 接 口 A supports 接 口 B, 而 B 又 supports C, 则 A 也 supports C。<br />
如 果 一 个 接 口 没 有 显 式 地 支 持 任 何 接 口 , 则 意 味 着 它 是 支 持 预 定 义 的 接 口 object。<br />
从 功 能 上 说 , 一 个 接 口 支 持 某 个 接 口 一 次 或 多 次 ( 直 接 间 接 都 算 ) 没 有 什 么 差 别 , 但 可 能 会 造 成 对 象<br />
表 示 上 的 差 别 。<br />
在 类 的 实 现 中 使 用 supports 时 , 会 导 致 This 不 仅 可 以 与 构 造 类 型 一 道 使 用 , 也 可 以 用 于 任 意 私 有<br />
支 持 的 对 象 类 型 。<br />
SupportsQualification :<br />
supports InterfaceName-comma-sep-list<br />
注 意 , 如 果 各 接 口 间 有 相 互 冲 突 的 谓 词 , 这 样 的 接 口 就 不 能 使 用 同 一 个 supports 限 定 符 。<br />
12
谓 词 冲 突 , 是 指 来 自 不 同 本 原 接 口 的 谓 词 有 相 同 的 名 称 及 变 元 数 。 而 本 原 接 口 , 是 指 谓 词 被 原 文 声 明<br />
的 接 口 , 它 是 相 对 于 用 supports 限 定 符 间 接 声 明 的 接 口 而 言 的 。<br />
因 此 , 如 果 一 个 接 口 在 supports 链 中 出 现 了 两 次 或 多 次 , 一 定 小 心 不 要 引 起 冲 突 。<br />
例 来 看 一 下 下 面 的 定 义 与 声 明 :<br />
interface aaa<br />
predicates<br />
insert : (integer X).<br />
end interface<br />
interface bbb<br />
supports aaa<br />
predicates<br />
insert : (integer X, string Comment).<br />
end interface<br />
interface cc<br />
supports aaa<br />
predicates<br />
extract : () -> integer.<br />
end interface<br />
interface dd<br />
supports aaa, bbb, cc<br />
predicates<br />
extract : (string Comment) -> integer.<br />
end interface<br />
下 面 是 在 dd 中 找 到 的 全 部 谓 词 的 表 ( 按 深 度 遍 历 ):<br />
predicates<br />
insert : (integer).<br />
% dd -> aaa<br />
insert : (integer).<br />
% dd -> bbb -> aaa<br />
insert : (integer, string). % dd -> bbb<br />
insert : (integer).<br />
% dd -> cc -> aaa<br />
extract : () -> integer. % dd -> cc<br />
extract: : (string) -> integer. % dd<br />
这 里 有 些 谓 词 是 相 同 的 , 因 此 实 际 上 dd 中 含 有 的 成 员 如 下 :<br />
predicates<br />
insert : (integer).<br />
% 本 原 接 口 : aaa<br />
insert : (integer, string). % 本 原 接 口 : bbb<br />
extract : () -> integer. % 本 原 接 口 : cc<br />
extract : (string) -> integer. % 本 原 接 口 : dd<br />
例 考 虑 如 下 接 口 :<br />
interface aaa<br />
predicates<br />
insert : (integer X).<br />
end interface<br />
interface bbb<br />
13
predicates<br />
insert : (integer X).<br />
end interface<br />
interface cc<br />
supports aaa, bbb<br />
end interface<br />
% 有 冲 突 的 接 口<br />
接 口 cc 是 不 合 法 的 , 因 为 在 aaa 中 支 持 的 insert/1 以 aaa 为 本 原 接 口 , 而 在 bbb 中 支 持 的 insert/1<br />
以 bbb 为 本 原 接 口 。<br />
Classes( 类 )<br />
类 声 明 向 外 界 定 义 了 类 的 外 观 , 外 界 可 以 看 到 和 准 确 地 使 用 类 声 明 中 记 述 过 的 实 体 。 我 们 说 , 类 声 明<br />
规 定 了 类 的 公 有 部 分 。<br />
类 声 明 可 以 含 有 常 数 和 域 定 义 , 以 及 谓 词 声 明 。<br />
如 果 一 个 类 说 明 了 一 个 构 造 类 型 ConstructionType, 则 它 可 以 构 造 此 种 类 型 的 对 象 。 可 以 构 造 对<br />
象 的 类 至 少 有 一 个 构 造 器 , 但 也 可 以 声 明 多 个 。 没 有 显 式 声 明 任 何 构 造 器 的 类 , 都 自 动 地 拥 有 缺 省 构 造 器<br />
( 即 new/0)。<br />
对 象 是 通 过 调 用 类 的 构 造 器 构 造 出 来 的 。 在 初 始 化 继 承 的 类 时 也 要 用 构 造 器 。<br />
类 声 明 中 所 提 到 的 一 切 是 属 于 类 的 , 而 不 是 属 于 它 所 构 造 的 对 象 的 。 与 对 象 有 关 的 一 切 , 都 要 在 这 个<br />
类 所 构 造 的 对 象 的 构 造 类 型 中 声 明 。<br />
任 何 类 声 明 ClassDeclaration 都 必 须 伴 有 类 实 现 classImplementation。 在 类 声 明 中 声 明 的 谓 词 的<br />
定 义 / 实 现 是 由 类 实 现 提 供 的 。 同 样 , 由 类 构 造 的 对 象 所 支 持 的 谓 词 定 义 也 是 由 类 实 现 提 供 的 。 这 两 种 谓 词<br />
都 可 以 由 子 句 实 现 , 但 对 象 谓 词 还 可 从 其 它 类 继 承 来 实 现 。<br />
需 要 特 别 指 出 , 类 声 明 对 代 码 继 承 没 有 作 任 何 说 明 。 代 码 继 承 完 全 是 “ 私 事 儿 ”, 只 能 在 类 实 现 中 说<br />
明 ( 这 与 许 多 其 它 面 向 对 象 的 语 言 不 同 , 是 要 在 implementation 中 隐 藏 所 有 的 实 现 细 节 )。<br />
如 果 类 没 有 说 明 构 造 类 型 ConstructionType, 则 这 个 类 不 能 产 生 任 何 对 象 ; 此 时 这 个 类 的 角 色 与<br />
其 说 是 “ 类 ” 还 不 如 说 是 个 模 块 更 恰 当 。<br />
ClassDeclaration :<br />
class ClassName ConstructionType-opt ScopeQualifications Sections end class<br />
ClassName-opt<br />
ConstructionType :<br />
: InterfaceName<br />
ClassName :<br />
LowerCaseIdentifier<br />
类 声 明 结 尾 处 的 ClassName( 如 果 要 写 的 话 ) 必 须 与 开 头 的 那 个 完 全 一 样 。<br />
允 许 用 类 的 名 字 ClassName 指 定 该 类 构 造 类 型 的 接 口 名 字 ConstructionType, 就 是 说 可 以 这 样 :<br />
class interfaceAndClassName : interfaceAndClassName<br />
要 注 意 , 类 和 接 口 都 可 以 声 明 域 和 常 数 , 它 们 之 间 必 须 没 有 冲 突 , 因 为 它 们 都 是 在 相 同 的 名 称 空 间 的<br />
( 它 们 只 能 由 相 同 的 接 口 或 类 的 名 称 来 限 定 了 )。<br />
ScopeQualifications 只 能 用 open 限 定 符 。<br />
14
Sections 必 须 是 下 面 的 种 类 :<br />
• Constants 段<br />
• domains 段<br />
• predicates 段<br />
• constructors 段<br />
• 条 件 段<br />
只 有 当 类 中 说 明 了 ConstructionType 时 ,constructors 段 才 是 合 法 的 。<br />
在 条 件 (conditional) 段 中 的 所 有 段 也 必 须 是 这 些 种 类 的 。<br />
Implementations ( 实 现 )<br />
一 个 类 的 实 现 , 用 于 提 供 在 该 类 声 明 中 声 明 的 谓 词 和 构 造 器 的 定 义 , 以 及 由 这 个 类 构 造 的 对 象 支 持 的<br />
谓 词 的 定 义 。<br />
类 可 以 私 有 地 ( 即 在 其 实 现 中 ) 声 明 和 定 义 比 类 声 明 中 提 到 的 更 多 的 实 体 。 特 别 是 , 在 实 现 里 可 以 声<br />
明 事 实 数 据 库 , 而 事 实 数 据 库 可 以 用 于 承 载 类 和 对 象 的 状 态 。<br />
实 现 是 一 个 混 合 的 范 围 , 它 既 包 含 了 类 的 实 现 , 也 包 含 了 类 产 生 的 对 象 的 实 现 。 类 的 类 部 分 是 由 类 的<br />
所 有 对 象 共 享 的 , 而 对 象 部 分 , 则 仅 属 于 各 个 对 象 。 类 部 分 和 对 象 部 分 都 可 以 含 有 事 实 与 谓 词 , 而 域 、 函<br />
子 和 常 数 则 总 是 属 于 类 部 分 , 即 , 它 们 不 是 属 于 哪 个 对 象 个 体 的 。<br />
缺 省 时 , 所 有 在 一 个 类 实 现 中 声 明 的 谓 词 和 事 实 成 员 是 对 象 成 员 。 要 声 明 一 个 类 成 员 , 必 须 在 段 关 键<br />
字 ( 如 predicates、facts) 前 加 关 键 字 class。 在 这 样 的 段 中 声 明 的 所 有 成 员 是 类 成 员 。<br />
类 成 员 可 以 引 用 类 的 类 部 分 , 但 不 能 引 用 对 象 部 分 。<br />
而 另 一 方 面 , 对 象 成 员 既 可 以 访 问 类 的 类 部 分 也 可 以 访 问 类 的 对 象 部 分 。<br />
在 实 现 中 的 代 码 , 所 有 者 对 象 为 全 体 对 象 谓 词 所 包 容 。 而 包 容 的 所 有 者 对 象 , 可 以 直 接 由 特 殊 的 变 量<br />
This 来 访 问 。<br />
ClassImplementation :<br />
implement ClassName ScopeQualifications Sections end implement<br />
ClassName-opt<br />
类 实 现 结 尾 处 的 ClassName( 如 果 要 写 的 话 ) 必 须 与 类 实 现 开 头 的 一 致 。<br />
ScopeQualifications 必 须 是 如 下 的 种 类 :<br />
• supports 限 定 符<br />
• open 限 定 符<br />
• inherit 限 定 符<br />
• delegate 限 定 符<br />
supports 限 定 符 后 列 出 一 个 接 口 表 , 表 示 由 该 类 实 现 私 有 支 持 的 接 口 。<br />
delegate 限 定 符 委 派 来 自 接 口 的 对 象 谓 词 功 能 给 来 自 对 象 的 谓 词 , 它 可 以 如 同 事 实 变 量 一 样 地 存 储 。<br />
Sections 必 须 是 如 下 种 类 :<br />
• constants 段<br />
• resolve 限 定 符<br />
• delegate 限 定 符<br />
• domains 段<br />
• predicates 段<br />
• constructors 段<br />
• facts 段<br />
15
• clauses 段<br />
• conditional 段<br />
constructors 段 只 有 在 ClassName 类 说 明 了 constructionType 时 才 是 合 法 的 。<br />
说 明 ConstructionType 的 子 句 也 是 对 象 的 构 造 器 , 它 按 规 定 的 构 造 类 型 构 造 对 象 。<br />
例 下 面 这 个 例 子 , 要 说 明 类 事 实 在 类 的 对 象 间 共 享 , 而 对 象 事 实 则 不 是 共 享 的 。<br />
设 有 接 口 aa 和 类 aa_class:<br />
interface aa<br />
predicates<br />
setClassFact : (integer Value).<br />
getClassFact : () -> integer.<br />
setObjectFact : (integer Value).<br />
getObjectFact : () -> integer.<br />
end interface<br />
class aa_class : aa<br />
end class<br />
这 些 谓 词 分 别 从 类 事 实 与 对 象 事 实 中 存 取 值 :<br />
implement aa_class<br />
class facts<br />
classFact : integer := 0.<br />
facts<br />
objectFact : integer := 0.<br />
clauses<br />
setClassFact(Value) :-<br />
classFact := Value.<br />
getClassFact() = classFact.<br />
clauses<br />
setObjectFact(Value) :-<br />
objectFact := Value.<br />
getObjectFact() = objectFact.<br />
end implement aa_class<br />
设 有 目 标 为 :<br />
goal<br />
A1 = aa_class::new(),<br />
A2 = aa_class::new(),<br />
A1:setClassFact(1),<br />
A1:setObjectFact(2),<br />
ClassFact = A2:getClassFact(),<br />
ObjectFact = A2:getObjectFact().<br />
类 事 实 是 由 所 有 对 象 共 享 的 , 所 以 用 A1 设 置 类 事 实 会 影 响 到 由 A2 取 得 的 值 , 因 而 ,ClassFact 的<br />
值 是 用 A1 设 置 的 那 个 值 。<br />
与 此 不 同 的 是 , 对 象 事 实 只 属 于 各 个 对 象 。 因 此 , 在 A1 中 设 置 的 对 象 事 实 不 会 影 响 存 储 在 A2 中 的<br />
值 。 这 样 ,ObjectFact 的 值 是 零 , 这 个 值 是 A2 初 始 化 时 的 值 。<br />
Construction( 构 造 )<br />
16
本 节 描 述 对 象 构 造 , 因 而 也 只 涉 及 那 些 构 造 对 象 的 子 句 。<br />
对 象 是 通 过 调 用 构 造 器 (constructor ) 构 造 出 来 的 。 而 构 造 器 则 是 在 类 的 声 明 和 实 现 中 的<br />
constructors 段 显 式 地 声 明 的 ( 参 见 缺 省 构 造 器 )。<br />
一 个 构 造 器 有 两 个 关 联 的 谓 词 :<br />
• 一 个 返 回 新 构 造 的 对 象 的 类 函 数<br />
• 一 个 用 于 初 始 化 继 承 对 象 的 对 象 谓 词<br />
相 关 的 对 象 谓 词 用 于 进 行 对 象 的 初 始 化 , 这 个 谓 词 只 能 在 本 身 的 类 和 继 承 的 类 中 由 构 造 器 来 调 用 ( 也<br />
就 是 基 于 类 的 初 始 化 )。<br />
相 关 的 类 函 数 是 隐 含 定 义 的 , 也 就 是 说 在 哪 儿 都 没 有 它 的 子 句 。 这 个 类 函 数 分 配 内 存 来 存 放 对 象 、 进<br />
行 对 象 的 初 始 化 并 调 用 对 象 构 造 器 来 创 建 对 象 。 最 后 , 作 为 构 造 器 的 执 行 结 果 , 返 回 构 造 的 对 象 。 因 此 ,<br />
在 构 造 器 的 子 句 被 调 用 之 前 :<br />
• 所 有 具 有 初 始 化 表 达 式 的 对 象 事 实 变 量 要 被 初 始 化<br />
• 所 有 具 有 子 句 的 对 象 事 实 要 从 这 些 子 句 开 始 被 初 始 化<br />
在 构 造 器 的 子 句 被 调 用 之 前 , 这 个 初 始 化 也 会 传 递 地 进 行 到 所 有 继 承 的 子 对 象 。<br />
构 造 器 子 句 必 须 要 :<br />
• 初 始 化 那 些 在 进 入 之 前 没 有 初 始 化 的 single 对 象 事 实 及 对 象 事 实 变 量<br />
• 初 始 化 所 有 子 对 象<br />
构 造 器 子 句 还 可 以 做 些 其 它 的 事 , 但 它 必 须 完 成 上 述 初 始 化 工 作 , 以 确 保 对 象 构 造 后 是 有 效 的 。<br />
注 意 : 在 构 造 期 间 对 象 可 能 是 无 效 的 , 要 避 免 访 问 未 初 始 化 的 对 象 部 分 ( 参 看 构 造 对 象 的 规 则 )。<br />
缺 省 构 造 器<br />
缺 省 构 造 器 不 需 要 输 入 参 数 , 名 为 new/0。 如 果 构 造 对 象 的 类 在 其 类 声 明 中 没 有 声 明 任 何 构 造 器 ,<br />
则 意 味 着 在 类 声 明 部 分 隐 含 地 声 明 了 缺 省 的 构 造 器 ( 即 new/0)。 这 也 意 味 着 每 个 类 至 少 有 一 个 构 造 器 ,<br />
因 此 , 这 样 写 :<br />
class aaa<br />
end class aaa<br />
与 下 面 的 写 法 , 结 果 是 一 样 的 :<br />
class aaa<br />
constructors<br />
new : ().<br />
end class aaa<br />
显 式 地 重 新 声 明 缺 省 构 造 器 也 是 合 法 的 。<br />
不 必 定 义 ( 也 就 是 说 , 实 现 ) 缺 省 构 造 器 , 如 果 不 定 义 , 则 隐 含 地 假 设 有 一 个 没 有 什 么 影 响 的 定 义 。<br />
因 此 , 如 果 有 一 个 构 造 器 aaa, 写 :<br />
implement aaa<br />
end implement aaa<br />
与 写 成 下 面 这 样 是 一 样 的 :<br />
implement aaa<br />
clauses<br />
new().<br />
17
end implement aaa<br />
注 意 , 只 是 在 下 面 这 样 的 情 况 中 , 类 才 有 一 个 缺 省 构 造 器 :<br />
• 这 个 类 没 有 公 开 地 声 明 任 何 构 造 器<br />
• 或 是 声 明 了 一 个 new/0 作 为 构 造 器<br />
也 可 以 反 过 来 说 , 如 果 是 下 述 情 况 , 一 个 类 就 没 有 缺 省 的 构 造 器 :<br />
• 这 个 类 公 开 地 声 明 了 构 造 器<br />
• 它 声 明 的 不 是 以 new/0 作 为 构 造 器<br />
例 设 有 接 口 aa, 考 查 下 面 的 代 码 :<br />
class aa_class : aa<br />
end class<br />
类 aa_class 没 有 声 明 构 造 器 , 所 以 , 它 隐 含 地 声 明 了 缺 省 构 造 器 。 因 而 , 可 以 这 样 创 建 一 个 aa_class<br />
类 的 对 象 :<br />
goal<br />
_A = aa_class::new().<br />
% 隐 含 声 明 的 缺 省 构 造 器<br />
例 实 现 隐 含 声 明 的 aa_class 类 的 缺 省 构 造 器 是 合 法 的 :<br />
implement aa_class<br />
clauses<br />
new() :-<br />
...<br />
end implement<br />
例 bb_class 类 显 式 地 声 明 了 一 个 构 造 器 , 因 为 它 不 是 缺 省 构 造 器 , 这 个 类 就 没 有 缺 省 构 造 器 。<br />
class bb_class : aa<br />
constructors<br />
newFromFile : (file File).<br />
end class<br />
例 cc_class 类 声 明 了 构 造 器 newFromFile/1, 但 同 时 也 声 明 了 缺 省 构 造 器 new/0, 所 以 显 然<br />
它 有 缺 省 构 造 器 new/0:<br />
class cc_class : aa<br />
constructors<br />
new : ().<br />
newFromFile : (file File).<br />
end class<br />
% 缺 省 构 造 器<br />
私 有 构 造 器<br />
在 类 实 现 里 , 还 可 以 声 明 “ 私 有 的 ” 构 造 器 。 在 下 面 的 情 况 中 , 可 能 是 有 这 个 需 要 的 :<br />
1. 当 某 个 谓 词 要 返 回 一 个 construction type 的 对 象 时 , 在 类 实 现 中 就 可 以 声 明 、 实 现 并 调 用<br />
“ 私 有 的 ” 构 造 器 来 创 建 这 样 的 对 象<br />
2. 当 某 个 类 里 声 明 了 几 个 “public” 的 构 造 器 、 而 这 些 构 造 器 中 有 很 多 相 同 部 分 时 , 用 一 个 在<br />
类 实 现 中 声 明 的 “ 私 有 的 ” 构 造 器 来 实 现 这 个 “ 相 同 部 分 ” 也 是 合 理 的 。 所 有 这 些 公 共 的 构<br />
18
造 器 的 子 句 只 需 要 调 用 这 个 私 有 的 构 造 器 来 实 现 “ 相 同 部 分 ”。<br />
注 意 , 在 一 个 可 以 构 造 对 象 的 类 中 , 如 果 在 类 声 明 中 没 有 声 明 任 何 构 造 器 , 则 意 味 着 隐 含 地 声 明 了 缺<br />
省 构 造 器 new/0, 这 和 在 类 实 现 中 是 否 声 明 私 有 构 造 器 无 关 。 这 样 一 来 , 可 以 这 样 做 :<br />
子 对 象 的 构 造<br />
interface aa<br />
end interface<br />
class aa : aa<br />
end class<br />
implement aa<br />
constructors<br />
myCreate : ().<br />
clauses<br />
myCreate() :-<br />
...<br />
end implement<br />
% 程 序 代 码<br />
...<br />
Obj = aa::new(), % 这 是 隐 含 声 明 的 缺 省 的 类 构 造 器<br />
...<br />
所 有 构 造 器 都 要 负 责 把 构 造 的 对 象 初 始 化 成 有 效 的 状 态 。 为 要 得 到 这 样 的 有 效 状 态 , 所 有 子 对 象 ( 即<br />
继 承 的 类 ) 也 必 须 初 始 化 。<br />
子 对 象 的 初 始 化 可 以 用 下 述 二 种 方 法 之 一 进 行 : 程 序 员 调 用 被 继 承 类 的 构 造 器 , 或 是 自 动 地 调 用 缺 省<br />
构 造 器 。 后 者 要 求 被 继 承 类 确 实 有 一 个 缺 省 构 造 器 , 这 个 缺 省 构 造 器 是 显 式 声 明 或 是 隐 含 声 明 的 无 关 紧 要 。<br />
如 果 被 继 承 类 没 有 缺 省 构 造 器 , 就 必 须 显 式 地 调 用 别 的 构 造 器 。 被 继 承 类 构 造 器 的 缺 省 调 用 时 刻 是 紧<br />
接 着 初 始 化 事 实 变 量 和 事 实 的 子 句 之 后 , 在 进 入 到 构 造 器 子 句 之 前 。<br />
被 继 承 类 的 构 造 器 调 用 是 按 不 返 回 值 的 模 式 进 行 的 。 如 果 按 返 回 值 的 版 本 来 做 调 用 , 实 际 上 就 创 建 了<br />
一 个 对 象 , 而 不 是 对 This 调 用 构 造 器 ( 参 看 下 面 的 例 子 )。<br />
例 这 个 bb_class 类 的 实 现 继 承 自 类 aa_class,bb_class 类 的 缺 省 构 造 器 调 用 aa_class 类 的<br />
一 个 构 造 器 , 创 建 一 个 新 的 cc_class 类 的 对 象 :<br />
implement bb_class inherits aa_class<br />
clauses<br />
new() :-<br />
C = cc_class::new(), % 创 建 一 个 cc_class 的 对 象<br />
aa_class::newC(C).<br />
...<br />
end implement<br />
% 对 继 承 的 子 对 象 调 用 构 造 器<br />
例 如 果 基 类 不 是 显 式 构 造 的 , 那 它 就 是 用 缺 省 构 造 器 隐 含 构 造 的 , 这 样 的 话 , 写 :<br />
implement bbb<br />
inherits aaa<br />
clauses<br />
myNew() :-<br />
doSomething().<br />
end implement bbb<br />
和 下 面 的 写 法 是 一 样 的 :<br />
19
implement bbb<br />
inherits aaa<br />
clauses<br />
myNew() :-<br />
aaa::new(),<br />
doSomething().<br />
end implement bbb<br />
如 果 aaa 没 有 缺 省 构 造 器 , 这 当 然 就 会 出 错 。<br />
注 意 , 这 个 规 则 当 然 也 可 以 和 前 面 在 缺 省 构 造 器 讨 论 过 的 规 则 结 合 起 来 , 写<br />
implement bbb<br />
inherits aaa<br />
end implement bbb<br />
与 写 成 下 面 的 样 子 ( 根 据 前 面 缺 省 构 造 器 在 中 讨 论 过 的 规 则 ) 是 完 全 相 同 的 :<br />
implement bbb<br />
inherits aaa<br />
clauses<br />
new().<br />
end implement bbb<br />
与 写 成 下 面 的 样 子 ( 按 刚 讨 论 过 的 规 则 ) 也 是 相 同 的 :<br />
implement bbb<br />
inherits aaa<br />
clauses<br />
new() :-<br />
aaa::new().<br />
end implement bbb<br />
single( 对 象 ) 事 实 的 初 始 化<br />
如 同 所 有 构 造 器 必 须 要 初 始 化 / 构 造 子 对 象 一 样 , 它 也 必 须 要 在 第 一 次 引 用 之 前 初 始 化 一 个 对 象 的 所 有<br />
的 事 实 。<br />
注 意 ,single 类 事 实 只 能 由 子 句 初 始 化 , 因 为 它 们 不 是 与 哪 个 对 象 关 联 的 , 类 事 实 在 第 一 个 对 象 创<br />
建 之 前 就 可 以 访 问 了 。<br />
例 这 个 例 子 表 明 (1) 如 何 用 表 达 式 初 始 化 一 个 事 实 变 量 ;(2) 如 何 用 子 句 初 始 化 一 个 single 事 实<br />
(point);(3) 如 何 在 构 造 器 里 初 始 化 一 个 single 事 实 ;(4) 在 哪 儿 调 用 被 继 承 类 的 缺 省 构 造 器 :<br />
implement bb_class inherits aa_class<br />
facts<br />
counter : integer := 0.<br />
point : (integer X, integer Y) single.<br />
c : (cc C) single.<br />
clauses<br />
point(0, 1).<br />
% 创 建 了 对 象 ,counter 和 point 在 进 入 之 前 初 始 化 了<br />
% 缺 省 构 造 器 aa_class::new/0 在 进 入 之 前 也 被 调 用 了<br />
20
new() :-<br />
C = cc_class::new(),<br />
assert(c(C)).<br />
...<br />
end implement<br />
委 托 构 造<br />
除 了 直 接 在 构 造 器 中 构 造 一 个 对 象 , 这 个 工 作 也 可 以 委 托 给 同 一 个 类 的 其 它 构 造 器 。 这 只 需 要 调 用 其<br />
它 的 构 造 器 ( 不 返 回 值 的 版 本 ) 就 可 以 了 。 委 托 构 造 时 , 必 须 要 确 保 对 象 真 的 被 构 造 了 , 而 且 还 不 能 重 复<br />
构 造 。single 事 实 可 以 多 次 赋 值 , 所 以 不 会 构 造 重 复 了 , 而 继 承 的 类 , 只 能 在 对 象 构 造 时 进 行 一 次 初 始 化 。<br />
例 这 个 例 子 表 明 了 委 托 构 造 的 一 个 典 型 应 用 , 构 造 器 new/0 用 缺 省 值 调 用 另 一 个 构 造 器<br />
newFromC/1。<br />
构 造 对 象 的 规 则<br />
implement aa_class<br />
facts<br />
c : (cc C) single.<br />
clauses<br />
new() :-<br />
C = cc_class::new(),<br />
newFromC(C).<br />
newFromC(C) :-<br />
assert(c(C)).<br />
...<br />
end implement<br />
程 序 员 必 须 保 证 :<br />
• 所 有 子 对 象 只 被 初 始 化 / 构 造 了 一 次<br />
• 所 有 single 事 实 被 初 始 化 了 ( 至 少 一 次 )<br />
• 在 初 始 化 / 构 造 之 前 没 有 子 对 象 被 引 用<br />
• 在 初 始 化 之 前 没 有 single 事 实 被 使 用<br />
在 编 译 时 编 译 器 对 这 些 问 题 的 检 测 是 没 有 什 么 保 证 的 。 编 译 器 可 能 会 给 出 一 个 运 行 时 确 认 , 也 可 能 会<br />
不 安 全 地 忽 略 这 样 的 运 行 时 确 认 。<br />
This<br />
对 象 谓 词 总 是 被 应 用 在 一 个 对 象 上 , 这 个 对 象 带 有 对 象 事 实 并 为 对 象 谓 词 的 实 现 所 包 容 。 对 象 谓 词 可<br />
以 访 问 到 这 个 暗 含 的 对 象 , 我 们 称 这 个 对 象 为 This。 可 以 隐 式 和 显 式 两 种 方 式 访 问 This。<br />
显 式 This<br />
在 每 个 对 象 谓 词 的 每 个 子 句 中 , 变 量 This 都 是 隐 含 定 义 了 的 并 绑 定 于 This, 也 就 是 其 成 员 谓 词 正 在<br />
执 行 的 那 个 对 象 。<br />
隐 式 This<br />
21
在 一 个 对 象 成 员 谓 词 的 子 句 里 , 可 以 直 接 调 用 其 它 对 象 成 员 谓 词 , 因 为 隐 含 地 设 定 了 This 来 进 行 这 种<br />
操 作 。 超 类 的 成 员 也 可 以 直 接 被 调 用 , 只 要 需 要 调 用 的 方 法 是 明 确 的 就 行 ( 参 看 范 围 与 可 见 性 )。 同 样 ,<br />
也 可 以 访 问 存 储 在 This 中 的 对 象 事 实 。<br />
This 与 继 承<br />
[ 注 意 这 一 段 的 内 容 有 可 能 发 生 变 化 , 因 为 关 于 语 言 的 这 个 问 题 正 打 算 作 更 动 。]<br />
This 指 的 对 象 , 总 是 属 于 在 使 用 This 的 那 个 类 的 , 如 果 这 个 类 是 被 其 它 的 类 继 承 的 , 仍 然 如 此 。<br />
设 接 口 aa 声 明 如 下 :<br />
interface aa<br />
predicates<br />
action : ().<br />
doAction : ().<br />
end interface<br />
而 类 aa_class 声 明 如 下 :<br />
其 实 现 是 :<br />
则 如 下 目 标 :<br />
写 出 来 的 是 :<br />
class aa_class : aa<br />
end class<br />
implement aa_class<br />
clauses<br />
action() :-<br />
doAction(),<br />
This:doAction().<br />
doAction() :-<br />
write("aa_class::doAction"), nl.<br />
end implement<br />
goal<br />
A = aa_class::new(),<br />
A:action().<br />
aa_class::doAction<br />
aa_class::doAction<br />
再 来 考 虑 如 下 声 明 的 类 bb_class:<br />
其 实 现 是 :<br />
class bb_class : aa<br />
end class<br />
implement bb_class inherits aa_class<br />
clauses<br />
doAction() :-<br />
22
write("bb_class::doAction"), nl.<br />
end implement<br />
这 样 的 目 标 :<br />
goal<br />
B = bb_class::new(),<br />
B:action().<br />
写 出 来 的 也 是 :<br />
aa_class::doAction<br />
aa_class::doAction<br />
因 为 在 类 aa_class 中 ( 显 式 和 隐 式 ) 的 This 都 指 的 是 类 aa_class 的 对 象 。<br />
现 在 来 看 另 一 个 例 子 :<br />
interface iName<br />
predicates<br />
className : () -> string Class.<br />
name: () -> string Class.<br />
nameThis: () -> string Class.<br />
end interface iName<br />
class aaa : iName<br />
end class aaa<br />
implement aaa<br />
clauses<br />
className() = "aaa".<br />
clauses<br />
name() = className().<br />
clauses<br />
nameThis() = This:className().<br />
end implement aaa<br />
class bbb : iName<br />
end class bbb<br />
implement bbb<br />
inherits aaa<br />
clauses<br />
className() = "bbb".<br />
end implement bbb<br />
goal<br />
OOO = bbb::new(),<br />
Class1 = OOO:name(),<br />
Class2 = OOO:nameThis().<br />
bbb 类 从 aaa 继 承 了 name 和 nameThis 的 定 义 , 但 再 实 现 了 className。 在 目 标 中 我 们 创 建 了<br />
一 个 bbb 对 象 , 在 它 的 基 础 上 我 们 调 用 name 和 nameThis。<br />
name 谓 词 直 接 调 用 className, 而 nameThis 调 用 This:className, 它 们 的 效 果 是 不 同 的 。<br />
name 谓 词 调 用 的 className 是 在 aaa 中 定 义 的 。 但 nameThis 调 用 的 className 则 是 定 义 在 This<br />
23
上 的 , 其 实 就 是 bbb::className, 因 为 This 是 一 个 bbb 对 象 。<br />
总 之 ,Class1 的 绑 定 值 是 “aaa”, Class2 而 则 是 “bbb”。<br />
像 nameThis 那 样 在 父 类 中 调 用 子 类 , 是 在 共 享 父 类 中 实 现 一 般 功 能 的 常 用 方 法 。 而 一 般 功 能 则 要<br />
依 靠 子 类 的 对 非 一 般 功 能 的 提 炼 区 分 。<br />
再 看 一 下 这 个 类 :<br />
interface iTest<br />
predicates<br />
test : () -> string Name.<br />
end interface iTest<br />
class ccc : iTest<br />
end class ccc<br />
implement ccc<br />
inherits aaa<br />
clauses<br />
test() = aaa::nameThis().<br />
end implement ccc<br />
ccc 也 继 承 于 aaa, 因 此 这 也 就 意 味 着 ccc 支 持 接 口 iName( 私 有 地 )。 当 aaa 调 用 This:className<br />
时 , 它 调 用 的 是 ccc 提 供 的 东 西 , 而 这 刚 好 又 是 继 承 自 aaa 的 。<br />
再 看 下 面 这 个 例 子 :<br />
class ddd : name<br />
end class ddd<br />
implement ddd<br />
inherits bbb<br />
clauses<br />
className() = "ddd".<br />
end implement ddd<br />
goal<br />
OOO = ddd::new(),<br />
Class1 = OOO:name(),<br />
Class2 = OOO:nameThis().<br />
ddd 继 承 自 bbb, 而 后 者 是 继 承 自 aaa 的 。 当 调 用 nameThis 时 其 实 调 用 的 是 aaa::nameThis,<br />
而 它 调 用 的 是 This:className。 在 这 里 ,This 是 ddd 对 象 , 因 而 实 际 的 调 用 成 了 ddd::className。<br />
总 之 , 对 This:className 的 调 用 最 后 指 向 支 持 含 有 className 的 接 口 的 子 类 。<br />
Inherits 限 定 符<br />
这 个 限 定 符 用 于 说 明 一 个 实 现 是 继 承 自 一 个 或 多 个 类 的 。 继 承 只 对 类 的 对 象 部 分 有 影 响 。<br />
由 其 它 的 类 继 承 的 目 的 , 是 要 从 那 些 类 中 继 承 行 为 。 当 cc 类 继 承 aa 类 , 意 味 着 cc 类 的 实 现 自 动 隐 含<br />
地 ( 私 有 的 ) 支 持 aa 类 的 构 造 类 型 ( 接 口 )。 当 然 , 如 果 类 aa 的 实 现 已 经 显 式 地 支 持 了 cc 的 构 造 类 型 ,<br />
它 们 之 间 就 没 什 么 分 别 了 。<br />
因 此 , 要 注 意 同 一 个 谓 词 , 比 如 说 p, 不 能 在 cc 类 的 构 造 类 型 接 口 中 声 明 又 在 被 继 承 的 aa 类 构 造 类 型<br />
接 口 中 声 明 ( 编 译 器 能 检 测 出 这 个 问 题 并 产 生 错 误 报 告 说 一 个 谓 词 在 两 个 地 方 作 了 声 明 )。 对 这 个 问 题 再<br />
稍 微 仔 细 地 讨 论 一 下 。 假 设 cc 类 有 一 个 构 造 类 型 接 口 cci, 而 另 一 个 aa 类 有 一 个 构 造 类 型 接 口 aai。 在 aai<br />
和 cci 接 口 中 都 声 明 同 一 个 谓 词 p, 只 要 aa 类 和 cc 类 独 立 的 , 编 译 器 都 不 会 检 测 出 问 题 。 但 一 旦 声 明 cc 类<br />
24
继 承 aa 类 , 则 cc 类 也 开 始 支 持 aai 接 口 。 这 样 一 来 ,cc 类 就 遇 到 了 两 个 p 谓 词 的 声 明 , 这 个 问 题 就 会 产 生<br />
编 译 时 的 错 误 。 要 避 免 谓 词 p 声 明 的 这 种 不 确 定 性 , 只 能 在 cci 接 口 声 明 中 使 用 Predicates from Interface<br />
段 , 如 下 :<br />
interface cci<br />
predicates from aai<br />
p(), ...<br />
end interface cci<br />
对 象 谓 词 可 以 被 继 承 : 如 果 一 个 类 没 有 实 现 某 个 它 的 对 象 谓 词 , 但 它 所 继 承 的 一 个 类 实 现 了 这 个 谓 词 ,<br />
则 这 个 谓 词 就 可 以 用 于 这 个 类 。<br />
继 承 的 类 对 被 继 承 的 类 没 有 什 么 特 权 , 它 也 只 能 通 过 该 构 造 类 型 接 口 访 问 其 中 的 对 象 。<br />
继 承 必 须 是 明 确 的 。 如 果 一 个 类 自 己 定 义 了 谓 词 , 这 不 会 含 糊 , 因 为 这 个 谓 词 定 义 是 显 而 易 见 的 。 如<br />
果 只 有 一 个 被 继 承 类 支 持 这 个 谓 词 , 这 也 不 会 有 问 题 。 但 是 , 如 果 有 两 个 或 多 个 类 支 持 这 个 谓 词 , 是 哪 个<br />
类 提 供 的 定 义 就 模 糊 了 。 此 时 , 必 须 用 一 个 resolve 限 定 符 来 解 决 这 个 模 糊 问 题 ( 参 看 Resolve 限 定 符 )。<br />
在 当 前 类 的 对 象 谓 词 中 可 以 直 接 调 用 来 自 被 继 承 类 的 对 象 谓 词 , 因 为 隐 含 使 用 了 作 为 谓 词 所 有 者 的 内<br />
建 子 对 象 。 类 限 定 符 可 解 决 来 自 被 继 承 类 的 对 象 谓 词 调 用 模 糊 问 题 。<br />
Resolve 限 定 符<br />
InheritsQualification :<br />
inherits ClassName-comma-sep-list<br />
已 经 提 到 过 关 于 调 用 谓 词 的 模 糊 问 题 , 可 以 通 过 使 用 指 定 名 称 来 避 免 。 但 当 有 继 承 情 况 出 现 时 , 这 也<br />
还 有 问 题 。 看 下 面 这 个 例 子 :<br />
interface aa<br />
predicates<br />
p : () procedure ().<br />
...<br />
end interface<br />
class bb_class : aa<br />
end class<br />
class cc_class : aa<br />
end class<br />
class dd_class : aa<br />
end class<br />
implement dd_class inherits bb_class, cc_class<br />
end implement<br />
在 这 种 情 况 下 , 是 类 bb_class 还 是 类 cc_class 来 给 类 dd_class 提 供 aa 的 实 现 是 模 糊 的 ( 注 意 ,<br />
我 们 说 一 个 类 实 现 一 个 接 口 , 就 意 味 着 它 对 在 接 口 里 声 明 的 谓 词 提 供 定 义 )。<br />
当 然 可 以 在 dd_class 的 实 现 中 添 加 子 句 , 这 可 以 有 效 地 解 决 问 题 。 比 如 , 下 面 的 子 句 , 它 会 从<br />
bb_class 中 “ 输 出 ” 谓 词 p:<br />
clauses<br />
p() :- bb_class::p().<br />
25
但 这 样 一 来 , 就 并 非 从 bb 继 承 了 , 其 实 是 我 们 的 类 委 托 任 务 给 bb_class。<br />
为 要 解 决 这 样 的 模 糊 ( 真 的 是 继 承 而 非 委 托 ), 可 以 使 用 一 个 resolve 段 。 这 个 段 包 含 一 些 解 决 方 案 :<br />
ResolveQualification :<br />
resolve Resolution-comma-sep-list<br />
Resolution :<br />
InterfaceResolution<br />
PredicateFromClassResolution<br />
PredicateRenameResolution<br />
PpredicateExternallyResolution<br />
限 定 符 resolve 用 于 从 指 定 的 源 中 提 供 实 现 。<br />
谓 词 解 决 方 案<br />
PredicateFromClassResolution :<br />
PredicateNameWithArity from ClassName<br />
来 自 类 的 谓 词 解 决 方 案 , 由 指 定 的 类 提 供 该 谓 词 的 实 现 。<br />
对 一 个 类 的 谓 词 解 决 方 案 来 说 :<br />
• 该 类 必 须 实 现 了 要 解 决 的 谓 词 , 这 也 意 味 着 该 谓 词 必 须 要 与 被 继 承 的 那 个 谓 词 源 于 同 样 的 接 口<br />
• 该 类 已 经 出 现 在 inherits 段<br />
谓 词 重 命 名 解 决 方 案<br />
谓 词 重 命 名 解 决 方 案 , 是 指 由 另 一 个 不 同 名 称 的 谓 词 提 供 该 谓 词 的 实 现 。 这 个 谓 词 必 须 来 自 一 个 继 承<br />
的 类 , 其 类 型 、 模 式 及 流 样 式 必 须 要 完 全 匹 配 。<br />
接 口 解 决 方 案<br />
PredicateRenameResolution :<br />
PredicateNameWithArity from ClassName :: PredicateName<br />
接 口 解 决 方 案 用 来 从 一 个 继 承 的 类 中 提 供 完 整 的 接 口 。 因 而 , 这 个 解 决 方 案 就 是 简 单 地 说 该 接 口 中 的<br />
所 有 谓 词 应 该 由 相 应 的 类 来 解 决 。<br />
InterfaceResolution :<br />
interface InterfaceName from ClassName<br />
该 类 必 须 公 开 地 支 持 提 供 解 决 方 案 的 接 口 。<br />
如 果 谓 词 解 决 方 案 与 接 口 解 决 方 案 都 覆 盖 了 某 个 谓 词 名 , 则 会 使 用 谓 词 解 决 方 案 , 也 就 是 说 精 细 度 高<br />
的 解 决 方 案 优 先 。 当 数 个 接 口 覆 盖 一 个 谓 词 时 , 只 要 它 们 都 是 由 相 同 的 类 提 供 谓 词 的 解 决 方 案 的 , 也 是 这<br />
样 。 另 一 方 面 , 如 果 谓 词 的 解 决 方 案 来 自 不 同 的 类 , 就 必 须 要 用 谓 词 解 决 方 案 来 克 服 模 糊 问 题 。<br />
注 意 , 解 决 方 案 的 语 法 不 能 解 决 谓 词 对 不 同 类 的 不 同 重 载 问 题 。<br />
例 我 们 可 以 用 接 口 解 决 方 案 来 解 决 前 面 例 子 中 的 问 题 。 在 这 种 情 况 下 , 我 们 选 择 aa_class 的 实 现 继<br />
承 cc_class, 但 从 bb_class 继 承 p。<br />
implement dd_class<br />
26
外 部 解 决 方 案<br />
inherits bb_class, cc_class<br />
resolve<br />
interface aa from cc_class<br />
p from bb_class<br />
end implement<br />
谓 词 的 外 部 解 决 方 案 , 是 指 谓 词 根 本 就 不 在 类 本 身 实 现 , 而 是 使 用 外 部 的 库 。 外 部 解 决 方 案 只 适 用 于<br />
类 谓 词 , 对 象 谓 词 不 能 用 这 个 解 决 方 案 。<br />
重 要 的 是 , 调 用 协 议 、 链 接 名 及 参 数 类 型 要 符 合 实 现 库 的 要 求 。<br />
私 有 与 公 用 谓 词 都 可 以 使 用 外 部 解 决 方 案 。<br />
PredicateExternallyResolution : PredicateNameWithArity externally<br />
动 态 外 部 解 决 方 案<br />
谓 词 的 外 部 解 决 方 案 也 提 供 了 动 态 地 从 DLL 中 加 载 私 有 和 公 用 类 谓 词 的 语 法 , 其 为 :<br />
PredicateExternallyResolutionFromDLL :<br />
PredicateNameWithArity externally from DllNameWithPath<br />
DllNameWithPath :<br />
StringLiteral<br />
如 果 在 DLL DllNameWithPath 中 没 有 谓 词 predicateNameWithArity, 动 态 加 载 会 让 程 序 运 行<br />
下 去 , 直 到 程 序 实 际 调 用 这 个 没 有 找 到 的 谓 词 , 这 时 就 会 出 现 运 行 时 错 误 。DllNameWithPath 是 程 序<br />
运 行 的 机 器 上 的 DLL 的 路 径 , 它 可 以 是 绝 对 的 也 可 以 是 相 对 的 。 例 如 , 如 果 需 要 的 dll 是 在 应 用 程 序 所 在 位<br />
置 的 上 一 级 目 录 中 , 就 可 以 用 “../DllName”。 参 看 MSDN 中 的 动 态 库 搜 索 次 序 。<br />
终 结<br />
对 象 一 旦 无 法 为 程 序 所 用 , 就 可 以 被 终 结 了 。 在 本 语 言 的 语 义 中 没 有 准 确 地 说 对 象 什 么 时 候 被 终 结 ,<br />
能 保 证 的 是 : 只 要 程 序 还 能 访 问 某 个 对 象 , 它 就 不 会 被 终 结 。 实 际 上 对 象 的 终 结 , 是 当 它 被 垃 圾 收 集 器 废<br />
掉 的 时 候 。 终 结 是 构 造 的 对 立 面 , 是 把 对 象 从 内 存 中 清 除 出 去 。<br />
类 也 可 以 实 现 一 个 终 结 器 , 这 是 一 个 谓 词 , 一 个 对 象 终 结 时 调 用 它 ( 在 对 象 被 清 出 内 存 之 前 )。<br />
终 结 器 是 一 个 过 程 , 没 有 参 数 , 没 有 返 回 值 , 其 名 称 是 finalize。 这 个 谓 词 是 隐 含 声 明 的 , 不 能 在 程<br />
序 中 直 接 调 用 。<br />
终 结 器 的 主 要 目 的 是 为 了 能 释 放 外 部 资 源 , 但 是 并 没 有 限 制 它 能 够 做 什 么 。 使 用 终 结 器 要 小 心 , 前 面<br />
说 过 , 调 用 它 们 的 时 间 不 能 完 全 确 定 , 因 而 也 就 很 难 预 测 调 用 它 时 整 个 程 序 的 状 态 。<br />
注 意 , 不 可 能 从 在 终 结 器 中 的 对 象 撤 消 对 象 事 实 , 因 为 终 结 过 程 是 自 动 进 行 的 。<br />
程 序 终 止 前 , 所 有 对 象 都 要 被 终 结 ( 除 非 出 现 像 电 源 故 障 这 样 的 异 常 )。<br />
例 这 个 例 子 中 , 用 一 个 终 结 器 来 保 证 正 确 地 关 闭 数 据 库 的 连 接 :<br />
implement aa_class<br />
facts<br />
connection : databaseConnection.<br />
clauses<br />
27
Delegate 限 定 符<br />
finalize() :-<br />
connection:close().<br />
...<br />
end implement aa_class<br />
delegate 段 包 含 有 一 些 委 托 项 :<br />
DelegateQualification :<br />
delegate Delegation-comma-sep-list<br />
Delegation :<br />
PredicateDelegation<br />
InterfaceDelegation<br />
委 托 限 定 符 用 于 将 对 象 谓 词 的 实 现 委 托 给 指 定 的 源 。<br />
委 托 限 定 符 分 为 两 类 ,Predicate Delegation( 谓 词 委 托 ) 和 Interface Delegation( 接 口 委 托 )。<br />
接 口 委 托 用 于 将 一 个 接 口 中 声 明 的 全 体 对 象 谓 词 的 实 现 委 托 给 另 一 个 对 象 的 实 现 , 存 储 为 事 实 变 量 。 这 就<br />
是 说 , 接 口 委 托 就 是 将 该 接 口 声 明 的 所 有 谓 词 的 实 现 委 托 给 另 一 个 对 象 的 实 现 , 存 储 在 事 实 变 量 中 。<br />
委 托 段 与 相 应 的 ( 谓 词 / 接 口 ) 解 决 方 案 段 相 似 , 只 不 过 需 要 委 托 事 实 变 量 来 保 存 构 造 的 类 的 对 象 ,<br />
而 不 是 从 类 中 继 承 。<br />
谓 词 委 托<br />
对 象 谓 词 的 委 托 , 是 指 该 谓 词 的 功 能 委 托 给 由 事 实 变 量 FactVariable_of_InterfaceType 中 指<br />
定 的 对 象 中 的 谓 词 。<br />
PredicateDelegation :<br />
PredicateNameWithArity to FactVariable_of_InterfaceType<br />
要 委 托 一 个 谓 词 给 一 个 由 事 实 变 量 传 递 的 对 象 :<br />
• 事 实 变 量 FactVariable_of_InterfaceType 必 须 具 有 声 明 谓 词 predicateNameWithArity<br />
的 接 口 的 类 型 ( 或 子 类 型 )<br />
• 对 象 支 持 的 接 口 必 须 已 经 构 造 好 了 , 并 且 已 经 与 FactVariable_of_InterfaceType 事 实 变<br />
量 相 关 联 。<br />
看 一 下 下 面 的 例 子 :<br />
interface a<br />
predicates<br />
p1 : () procedure ().<br />
p2 : () procedure ().<br />
end interface<br />
interface aa<br />
supports a<br />
end interface<br />
class bb_class : a<br />
end class<br />
class cc_class : a<br />
28
end class<br />
class dd_class : aa<br />
constructors<br />
new : (a First, a Second).<br />
end class<br />
implement dd_class<br />
delegate p1/0 to fv1, p2/0 to fv2<br />
facts<br />
fv1 : a.<br />
fv2 : a.<br />
clauses<br />
new(I,J):-<br />
fv1 := I,<br />
fv2 := J.<br />
end implement<br />
后 面 , 它 就 可 以 构 造 a 类 型 的 对 象 , 并 将 其 赋 予 事 实 变 量 fv1 和 fv2, 来 定 义 对 象 , 这 个 对 象 的 类 就 是<br />
我 们 实 际 要 委 托 定 义 p1 和 p2 功 能 的 类 。 来 看 :<br />
goal<br />
O_bb = bb_class::new(),<br />
O_cc = cc_class::new(),<br />
O_dd = dd_class::new(O_bb, O_cc),<br />
O_dd : p1(),<br />
% 这 个 p1 来 自 O_bb 对 象<br />
O_dd : p2().<br />
% 这 个 p2 来 自 O_cc 对 象<br />
其 实 ,<strong>Visual</strong> <strong>Prolog</strong> 的 委 托 与 在 dd_class 的 实 现 中 添 加 子 句 明 确 地 指 出 要 从 哪 个 类 的 对 象 “ 输 出 ”<br />
谓 词 的 功 能 , 效 果 是 一 样 的 。 对 上 面 这 个 例 子 , 也 就 是 在 dd_class 的 实 现 中 添 加 下 面 的 子 句 :<br />
接 口 委 托<br />
clauses<br />
p1() :- fv1:p1().<br />
如 果 需 要 指 定 在 InterfaceName 接 口 中 声 明 的 所 有 谓 词 的 功 能 都 委 托 给 来 自 相 同 继 承 类 的 对 象 谓<br />
词 , 就 可 以 用 接 口 委 托 :<br />
InterfaceDelegation :<br />
interface InterfaceName to FactVariable_of_InterfaceType<br />
接 口 委 托 就 是 将 在 接 口 InterfaceName 中 声 明 的 所 有 谓 词 的 功 能 委 托 给 存 储 为 事 实 变 量<br />
FactVariable_of_InterfaceType 的 对 象 。 对 象 应 该 已 经 与 FactVariable_of_InterfaceType<br />
事 实 变 量 相 关 联 , 而 这 个 事 实 变 量 的 类 型 应 该 是 InterfaceName 的 ( 或 是 其 子 类 型 )。<br />
要 将 接 口 委 托 给 一 个 由 事 实 变 量 传 递 的 对 象 :<br />
• 事 实 变 量 FactVariable_of_InterfaceType 必 须 是 接 口 InterfaceName 的 类 型 ( 或 是 其<br />
子 类 型 )<br />
• 对 象 支 持 的 接 口 必 须 已 经 构 造 , 并 且 已 经 与 事 实 变 量 FactVariable_of_InterfaceType 相<br />
关 联 。<br />
谓 词 委 托 的 优 先 级 高 于 接 口 委 托 。 如 果 一 个 谓 词 两 个 委 托 都 做 了 , 也 就 是 做 了 谓 词 委 托 , 而 它 又 是 在<br />
一 个 接 口 中 声 明 的 , 这 个 接 口 又 做 了 委 托 , 这 时 , 将 实 现 高 优 先 级 的 谓 词 委 托 。<br />
29
Namespaces( 名 称 空 间 )<br />
名 称 空 间 可 以 用 于 避 免 名 称 冲 突 , 不 需 要 使 用 长 的 冷 僻 名 称 。 在 不 同 名 称 空 间 的 名 字 是 不 会 产 生 冲 突<br />
的 , 但 可 能 需 要 用 名 称 空 间 来 指 定 引 用 以 解 决 模 糊 问 题 。<br />
名 称 空 间 的 声 明 与 定 义 隐 含 地 使 用 NamespaceEntrance:<br />
NamespaceEntrance:<br />
namespace NamespaceIdentifier<br />
NamespaceIdentifier: one of<br />
LowercaseIdentifier<br />
LowercaseIdentifier \ NamespaceIdentifier<br />
简 单 地 说 ,NamespaceIdentifier 是 一 系 列 用 反 斜 杠 分 隔 的 小 写 标 识 。<br />
Namespace 的 入 口 与 区 域<br />
名 称 空 间 入 口 把 源 文 件 分 割 成 一 些 namespace regions( 名 称 空 间 区 域 )。 一 个 名 称 空 间 入 口 标<br />
志 着 一 个 名 称 空 间 区 域 的 起 始 , 这 个 区 域 结 束 于 下 一 个 名 称 空 间 入 口 或 是 文 件 的 结 尾 。 每 个 文 件 开 始 于<br />
root namespace( 根 名 称 空 间 )。<br />
名 称 空 间 区 域 不 会 受 #include 指 令 的 影 响 , 也 就 是 说 , 在 一 个 #include- 文 件 中 的 名 称 空 间 入 口 不<br />
会 改 变 包 括 文 件 的 名 称 空 间 区 域 。<br />
任 何 文 件 都 起 始 于 根 名 称 空 间 ( 即 使 它 是 被 包 括 在 另 一 个 文 件 中 的 内 部 名 称 空 间 也 是 这 样 )。<br />
任 何 在 一 个 名 称 空 间 区 域 中 汇 合 的 接 口 、 类 和 实 现 , 属 于 那 个 名 称 空 间 。<br />
例<br />
class aaa<br />
end class aaa<br />
namespace xxx<br />
class bbb<br />
end class bbb<br />
namespace xxx\yyy<br />
class ccc<br />
end class ccc<br />
这 个 文 件 分 成 了 三 个 区 域 ( 假 设 这 是 一 个 完 整 的 文 件 )。 第 一 个 区 域 是 根 名 称 空 间 (\), 第 二 个 区<br />
域 是 属 于 xxx 名 称 空 间 的 , 而 第 三 个 区 域 是 属 于 xxx\yyy 名 称 空 间 的 。 相 应 地 , 类 aaa 属 于 根 名 称 空 间 ,<br />
类 bbb 属 于 xxx 名 称 空 间 而 类 ccc 属 于 xxx\yyy 名 称 空 间 。<br />
namespaces 中 的 引 用 名<br />
如 果 ccc 是 在 名 称 空 间 xxx\yyy 中 的 一 个 类 , 那 么 ccc 的 全 称 (full name) 就 是 \xxx\yyy\ccc。<br />
30
最 前 面 的 反 斜 杠 表 示 是 从 根 名 称 空 间 开 始 的 。 类 / 接 口 总 是 可 以 用 全 称 来 唯 一 性 地 引 用 。<br />
Open namespaces<br />
全 称 有 时 并 不 方 便 , 我 们 可 以 用 开 放 的 名 称 空 间 来 使 用 简 短 的 名 称 。<br />
ScopeQualification: one of<br />
OpenQualification<br />
...<br />
OpenQualification: one of<br />
open NamespaceIdentifier \<br />
...<br />
开 放 的 名 称 空 间 是 由 结 尾 的 反 斜 杠 与 开 放 的 类 / 接 口 相 区 别 的 。<br />
例<br />
class aaa<br />
open xxx\yyy\<br />
...<br />
end class aaa<br />
名 称 空 间 xxx\yyy 在 aaa 中 是 开 放 的 。<br />
当 一 个 名 称 空 间 是 开 放 的 时 , 其 全 称 部 分 就 可 以 省 掉 。 如 , 全 称 是 \xxx\yyy\zzz\ccc::ddd 的 一<br />
个 域 , 可 以 在 aaa 中 用 zzz\ccc::ddd 来 引 用 , 因 为 xxx\yyy 是 开 放 的 。<br />
注 意 , 略 写 的 名 称 不 是 用 反 斜 杠 开 头 的 , 用 反 斜 杠 开 头 的 名 称 总 是 全 称 。<br />
属 于 某 个 范 围 ( 如 接 口 / 类 / 实 现 ) 的 名 称 空 间 , 在 那 个 范 围 内 部 是 ( 隐 含 地 ) 开 放 的 。<br />
Program Sections( 程 序 段 )<br />
以 下 各 段 用 于 在 范 围 内 声 明 和 定 义 实 体 。<br />
Section :<br />
ConstantsSection 常 数 段<br />
DomainsSection 域 段<br />
PredicatesSection 谓 词 段<br />
ConstructorsSection 构 造 器 段<br />
PropertiesSection 属 性 段<br />
FactsSection 事 实 段<br />
ClausesSection 子 句 段<br />
ConditionalSection 条 件 段<br />
上 面 的 段 并 不 会 都 出 现 在 所 有 类 型 的 范 围 内 , 详 细 情 况 请 参 考 接 口 、 类 声 明 和 类 实 现 。<br />
条 件 段 在 条 件 编 译 一 节 中 叙 述 。<br />
Domains( 域 )<br />
Domains 段<br />
31
域 段 在 当 前 范 围 中 定 义 了 一 组 域 ( 参 看 接 口 、 类 声 明 和 类 实 现 )。<br />
Domain 定 义<br />
DomainsSection:<br />
domains DomainDefinition-dot-term-list-opt<br />
域 定 义 在 当 前 范 围 中 对 一 个 命 名 了 的 域 作 详 细 说 明 。<br />
DomainDefinition:<br />
DomainName FormalTypeParameterList-opt = TypeExpression<br />
如 果 右 边 的 域 表 示 一 个 接 口 或 一 个 复 合 域 , 则 定 义 的 域 与 类 型 表 达 式 是 同 义 的 ( 等 价 的 )。 否 则 , 定<br />
义 的 域 就 是 类 型 表 达 式 表 示 的 域 的 子 类 型 。 这 里 , 域 名 DomainName 必 须 是 小 写 标 识 。<br />
有 的 地 方 必 须 用 域 名 而 不 是 类 型 表 达 式 :<br />
• 作 为 形 式 参 数 类 型 的 声 明 时 ;<br />
• 作 为 常 数 或 事 实 变 量 的 类 型 时 ;<br />
• 作 为 表 域 的 类 型 时 。<br />
类 型 表 达 式<br />
类 型 名<br />
类 型 表 达 式 表 示 一 种 类 型 。<br />
TypeExpression:<br />
TypeName<br />
CompoundDomain<br />
ListDomain<br />
PredicateDomain<br />
IntegralDomain<br />
RealDomain<br />
TypeVariable<br />
TypeApplication<br />
类 型 名 是 一 个 接 口 的 名 字 或 是 一 个 值 域 的 名 字 。 值 域 是 指 其 元 素 是 非 易 变 的 ( 不 可 更 改 的 ) 域 。<br />
这 里 我 们 可 以 说 , 对 象 是 属 于 相 应 于 接 口 名 的 域 , 具 有 易 变 的 状 态 , 而 其 它 的 域 则 是 非 易 变 的 。 因 此 ,<br />
实 际 上 值 类 型 就 是 除 了 对 象 类 型 而 外 的 所 有 的 东 西 。 类 型 名 , 显 而 易 见 是 表 示 相 应 于 已 有 域 的 名 称 的 类 型<br />
的 。<br />
TypeName:<br />
InterfaceName<br />
DomainName<br />
ClassQualifiedDomainName<br />
InterfaceName:<br />
LowercaseIdentifier<br />
DomainName:<br />
LowercaseIdentifier<br />
32
ClassQualifiedDomainName:<br />
ClassName::DomainName<br />
ClassName:<br />
LowercaseIdentifier<br />
这 里 ,InterfaceName 是 接 口 名 ,DomainName 是 值 域 名 而 ClassName 是 类 名 。<br />
例<br />
domains newDomain1 = existingDomain. newDomain2 = myInterface.<br />
在 上 面 这 个 例 子 中 , 分 别 用 域 名 existingDomain 和 接 口 名 myInterface 定 义 了 两 个 新 的 域 。<br />
复 合 域<br />
复 合 域 ( 也 称 为 代 数 数 据 类 型 ) 用 于 表 示 表 、 树 及 其 它 树 状 结 构 的 值 。 它 的 简 单 形 式 可 以 表 示 结 构 和<br />
枚 举 值 。 复 合 域 可 以 递 归 定 义 , 可 以 互 递 归 或 间 接 递 归 。<br />
CompoundDomain:<br />
Alignment-opt FunctorAlternative-semicolon-sep-list><br />
Alignment:<br />
align IntegralConstantExpression<br />
这 里 的 IntegralConstantExpression 是 一 个 表 达 式 , 在 编 译 时 必 须 能 计 算 得 出 整 数 值 。<br />
复 合 域 声 明 宣 布 了 一 个 函 子 选 项 表 , 还 带 有 可 选 的 alignment, 它 必 须 是 1、2 或 4。<br />
如 果 复 合 域 包 含 一 个 函 子 选 项 , 则 可 以 视 其 为 结 构 , 它 的 表 示 方 法 与 C 语 言 的 相 应 结 构 是 二 进 制 兼 容<br />
的 。<br />
FunctorAlternative:<br />
FunctorName FunctorName ( FormalArgument-comma-sep-list-opt )<br />
这 里 的 FunctorName 是 函 子 选 项 名 称 , 应 该 用 小 写 标 识 。<br />
FormalArgument:<br />
TypeExpression ArgumentName-opt<br />
这 里 的 ArgumentName 可 以 是 任 意 大 写 标 识 。 编 译 器 会 忽 略 它 。<br />
复 合 域 对 其 它 任 何 域 都 没 有 子 类 型 的 关 系 。 如 果 一 个 域 定 义 和 一 个 复 合 域 的 相 同 , 则 这 两 个 域 是 同 义<br />
类 型 的 而 不 是 子 类 型 。 也 就 是 说 , 这 两 个 域 是 不 同 名 称 相 同 类 型 的 。<br />
例<br />
domains<br />
t1 = ff(); gg(integer, t1).<br />
t1 是 一 个 有 两 个 选 项 的 复 合 域 , 第 一 个 选 项 是 零 元 函 子 ff, 而 第 二 个 选 项 是 二 元 函 子 gg, 它 带 有 一<br />
个 integer 和 一 个 域 项 t1 本 身 作 为 参 数 。 因 此 , 域 t1 是 递 归 定 义 的 。<br />
下 面 这 些 表 达 式 都 是 域 t1 的 项 :<br />
33
ff()<br />
gg(77, ff())<br />
gg(33, gg(44, gg(55, ff())))<br />
例<br />
domains<br />
t1 = ff(); gg(t2).<br />
t2 = hh(t1, t1).<br />
t1 是 有 两 个 选 项 的 复 合 域 , 第 一 个 选 项 是 零 元 函 子 ff, 而 第 二 个 选 项 是 一 元 函 子 gg, 它 以 域 项 t2 为<br />
参 数 。t2 也 是 一 个 复 合 域 , 有 一 个 选 项 函 子 hh, 这 个 函 子 以 两 个 t1 项 为 参 数 。 因 而 , 域 t1 和 t2 是 互 递 归<br />
的 。 下 面 这 些 项 都 是 域 t1 的 :<br />
ff()<br />
gg(hh(ff(), ff()))<br />
gg(hh(gg(hh(ff(), ff())), ff()))<br />
ggg(hh(ff(), g(hh(ff(), ff()))))<br />
gg(hh(gg(hh(ff(), ff())), gg(hh(ff(), ff()))))<br />
例 这 个 例 子 中 ,t1 和 t2 是 同 义 类 型 。<br />
domains<br />
t1 = f(); g(integer).<br />
t2 = t1.<br />
通 常 没 有 必 要 在 零 元 函 子 后 使 用 空 的 圆 括 号 。 但 在 域 定 义 中 , 如 果 仅 有 一 个 零 元 函 子 , 就 必 须 用 空 的<br />
圆 括 号 来 与 同 义 / 子 类 型 定 义 相 区 分 。<br />
例 t1 是 一 个 仅 有 一 个 零 元 函 子 的 复 合 域 , 而 t2 是 定 义 为 与 t1 同 义 的 。<br />
domains<br />
t1 = f().<br />
t2 = t1.<br />
List Domains( 表 域 )<br />
表 域 表 示 某 个 域 中 的 一 个 序 列 值 。 因 此 , 所 有 在 表 T 中 的 元 素 都 必 须 是 T 类 型 的 。<br />
ListDomain:<br />
TypeName *<br />
T* 是 T 元 素 表 的 类 型 。<br />
下 面 一 些 语 法 应 用 于 表 :<br />
ListExpression:<br />
[ Term-comma-sep-list-opt ]<br />
[ Term-comma-sep-list | Tail ]<br />
Tail:<br />
34
Term<br />
这 里 Tail 是 其 值 为 ListDomain 类 型 的 项 。 每 个 Term 都 应 该 是 typeName 类 型 的 。<br />
实 际 上 , 表 只 不 过 是 有 两 个 函 子 的 复 合 域 : 表 示 空 表 的 [] 和 表 示 表 头 HD 与 表 尾 TL 的 混 合 固 定 函 子<br />
[HD|TL]。 表 头 必 须 是 基 本 元 素 类 型 , 而 表 尾 必 须 是 相 应 类 型 的 表 。<br />
表 不 过 是 语 法 便 利 化 的 结 果 。<br />
[E1, E2, E3, ..., En | L ] 是 [E1 |[ E2 |[ ...[ En | L ]...]]] 的 简 化 。<br />
[E1, E2, E3, ..., En] 是 [E1, E2, E3, ..., En |[]] 的 简 化 , 而 后 者 又 是 [E1 |[ E2 |[ ...[ En |<br />
[] ]...]]] 的 简 化 。<br />
Predicate Domains( 谓 词 域 )<br />
谓 词 域 的 值 是 带 有 相 同 特 征 的 谓 词 , 而 “ 相 同 特 征 ” 指 的 是 相 同 的 参 数 与 返 回 类 型 、 相 同 的 流 样 式 和<br />
相 同 ( 或 更 强 的 ) 谓 词 模 式 。<br />
返 回 值 的 谓 词 称 为 function( 函 数 ), 而 不 返 回 值 的 谓 词 有 时 也 称 为 原 态 ( 普 通 ) 谓 词 , 以 强 调 其<br />
不 是 一 个 函 数 。<br />
PredicateDomain:<br />
( FormalArgument-comma-sep-list-opt ) ReturnArgument-opt<br />
PredicateModeAndFlow-list-opt CallingConvention-opt<br />
FormalArgument:<br />
PredicateArgumentType VariableName-opt<br />
Ellipsis<br />
ReturnArgument:<br />
-> FormalArgument<br />
PredicateArgumentType:<br />
TypeName<br />
AnonymousIdentifier<br />
VariableName:<br />
UpperCaseIdentifier<br />
谓 词 域 可 以 用 Ellipsis( 省 略 号 ) 参 数 作 为 FormalArgument-comma-sep-list 中 的 最 后 的<br />
FormalArgument。<br />
谓 词 域 可 以 用 AnonymousIdentifier 作 为 一 个 predicateArgumentType, 表 示 这 个 参 数 可 以 是<br />
任 意 类 型 的 。<br />
目 前 , 带 省 略 号 的 谓 词 域 只 能 用 在 谓 词 声 明 中 。<br />
在 域 定 义 中 的 谓 词 域 最 多 只 能 声 明 一 个 流 样 式 。<br />
PredicateModeAndFlow:<br />
PredicateMode-opt<br />
FlowPattern-list-opt<br />
Predicate Mode( 谓 词 模 式 )<br />
规 定 的 谓 词 模 式 适 用 于 其 后 流 样 式 表 中 的 各 个 成 员 。<br />
PredicateMode: one of<br />
35
erroneous<br />
failure procedure<br />
determ multi<br />
nondeterm<br />
谓 词 模 式 可 以 用 以 下 集 合 来 描 述 :<br />
erroneous = {}<br />
failure = {Fail}<br />
procedure = {Succeed}<br />
determ = {Fail, Succeed}<br />
multi = {Succeed, BacktrackPoint}<br />
nondeterm = {Fail, Succeed, BacktrackPoint}<br />
集 合 中 有 Fail 就 意 味 着 这 个 谓 词 可 以 失 败 , 有 succeed 意 味 着 可 以 成 功 , 有 BacktrackPoint 意<br />
味 着 可 以 由 有 效 的 回 溯 点 返 回 。<br />
如 果 一 个 集 合 ( 比 如 说 failure) 是 另 一 个 集 合 ( 比 如 说 nondeterm) 的 子 集 , 则 称 其 模 式 比 另 一<br />
个 强 , 也 就 是 failure 强 于 nondeterm。<br />
谓 词 域 实 际 上 包 含 了 所 有 规 定 的 ( 或 更 强 的 ) 模 式 的 谓 词 ( 带 有 合 适 的 类 型 和 流 样 式 )。<br />
对 构 造 器 声 明 谓 词 模 式 是 非 法 的 , 构 造 器 的 模 式 永 远 是 procedure。<br />
缺 省 的 谓 词 模 式 是 procedure。<br />
缺 省 流 样 式 表 示 所 有 参 数 都 用 于 输 入 。<br />
注 意 , 与 <strong>Visual</strong> <strong>Prolog</strong> v. 5.x 不 同 , 实 现 内 部 ( 即 对 一 个 局 部 谓 词 ) 要 求 的 流 及 模 式 不 是 源 于 谓 词<br />
的 用 法 。 现 在 , 在 对 局 部 谓 词 的 声 明 中 省 略 谓 词 模 式 表 示 是 procedure 而 省 略 流 样 式 表 示 所 有 参 数 是 输<br />
入 。<br />
如 果 在 一 个 实 现 内 部 需 要 明 确 地 规 定 一 个 谓 词 使 用 的 所 有 可 能 的 流 样 式 , 仍 然 可 以 把 这 个 责 任 交 给 编<br />
译 器 。 对 类 实 现 内 这 个 任 务 , 可 以 使 用 特 殊 的 流 样 式 anyflow。 在 此 情 况 下 , 编 译 时 编 译 器 会 按 照 谓 词<br />
的 用 法 得 到 需 要 的 流 样 式 。 但 如 果 在 流 样 式 前 anyflow 的 可 选 的 谓 词 模 式 缺 省 了 , 则 总 是 假 设 为<br />
procedure 模 式 。<br />
Flow Pattern( 流 样 式 )<br />
流 样 式 定 义 参 数 的 输 入 / 输 出 流 向 。 参 数 可 以 与 函 子 域 相 结 合 , 使 得 单 个 的 参 数 一 部 分 是 输 入 而 另 一<br />
部 分 是 输 出 。<br />
流 样 式 由 一 个 流 序 列 构 成 , 每 个 流 对 应 于 一 个 参 数 ( 第 一 个 流 对 应 第 一 个 参 数 ,… 等 等 )。<br />
FlowPattern:<br />
( Flow-comma-sep-list-opt ) AnyFlow<br />
Flow: one of<br />
i<br />
o<br />
FunctorFlow<br />
ListFlow<br />
Ellipsis<br />
省 略 流 必 须 与 省 略 参 数 相 对 应 , 因 而 它 只 能 是 流 样 式 中 的 最 后 一 个 流 。<br />
Ellipsis:<br />
...<br />
36
函 子 流 FunctorFlow 说 明 一 个 函 子 及 其 各 成 分 的 流 。 当 然 , 函 子 必 须 在 相 应 参 数 的 域 中 。<br />
FunctorFlow:<br />
FunctorName ( Flow-comma-sep-list-opt )<br />
函 子 流 声 明 中 不 能 含 有 省 略 流 。<br />
表 流 与 函 子 流 相 似 , 只 不 过 是 采 用 了 与 表 域 相 同 的 语 法 加 工 。<br />
ListFlow:<br />
[ Flow-comma-sep-list-opt ListFlowTail-opt]<br />
ListFlowTail:<br />
| Flow<br />
表 流 也 不 能 含 有 省 略 流 。<br />
声 明 谓 词 时 流 样 式 可 以 省 略 。 在 实 现 内 部 ( 即 对 局 部 谓 词 ) 需 要 的 流 样 式 得 自 于 谓 词 的 使 用 方 法 。 在<br />
接 口 或 类 声 明 内 部 ( 即 对 公 有 谓 词 ) 省 略 流 样 式 表 示 所 有 参 数 都 是 输 入 。<br />
特 殊 流 样 式 anyflow 只 能 在 局 部 谓 词 的 声 明 ( 即 在 类 实 现 内 部 的 谓 词 声 明 ) 中 使 用 。 它 表 示 准 确 的<br />
流 样 式 在 编 译 时 确 定 。 如 果 其 前 可 选 的 谓 词 模 式 省 略 了 , 表 示 谓 词 模 式 是 procedure。<br />
例<br />
domains<br />
pp1 = (integer Argument1).<br />
pp1 是 一 个 谓 词 域 。 这 个 具 有 pp1 类 型 的 谓 词 有 一 个 integer 参 数 。 因 为 没 有 写 出 流 样 式 , 表 示 这 个<br />
参 数 是 输 入 , 又 因 为 没 有 写 出 谓 词 模 式 , 表 示 谓 词 是 procedure。<br />
例<br />
domains<br />
pp2 = (integer Argument1) -> integer ReturnType.<br />
pp2 类 型 的 谓 词 有 一 个 integer 参 数 并 返 回 integer 类 型 的 值 。 因 而 ,pp2 是 一 个 函 数 域 , 具 有 pp2<br />
类 型 的 谓 词 实 际 上 是 函 数 。 因 为 没 有 说 明 流 样 式 , 所 以 参 数 是 输 入 的 , 谓 词 模 式 也 没 提 , 故 谓 词 是<br />
procedure 的 。<br />
例<br />
predicates<br />
ppp : (integer Argument1, integer Argument2) determ (o,i) (i,o) nondeterm (o,o).<br />
谓 词 ppp 有 两 个 integer 参 数 , 它 有 三 种 不 同 的 流 样 式 :(o,i) 和 (i,o) 是 determ 的 ,(o,o) 是<br />
nondeterm 的 。<br />
调 用 约 定<br />
调 用 约 定 确 定 了 参 数 等 如 何 传 递 给 谓 词 , 它 也 确 定 了 如 何 由 谓 词 名 得 到 链 接 名 。<br />
37
CallingConvention:<br />
language CallingConventionKind<br />
CallingConventionKind: one of<br />
c stdcall apicall prolog<br />
如 果 没 有 说 明 调 用 约 定 , 则 使 用 prolog 约 定 , 它 是 <strong>Prolog</strong> 谓 词 使 用 的 标 准 约 定 。<br />
c 调 用 约 定 遵 从 C/C++ 的 标 准 调 用 约 定 。 谓 词 的 链 接 名 是 谓 词 名 前 加 下 划 线 (_)。<br />
的 实 现 :<br />
stdcall 调 用 约 定 使 用 c 的 链 接 名 策 略 , 但 参 数 与 栈 的 处 理 规 则 有 不 同 。 下 表 说 明 了 stdcall 调 用 约 定<br />
特 征<br />
参 数 传 递 顺 序<br />
参 数 传 递 约 定<br />
栈 的 维 护 职 责<br />
名 字 的 装 饰<br />
大 小 写 转 换 约 定<br />
从 右 到 左<br />
实 现<br />
除 复 合 域 项 传 递 , 都 是 传 递 的 值 。 因 此 , 它 不 能 应 用 于 参 数 数 量 可 变 的 谓 词<br />
被 调 用 的 谓 词 从 栈 中 弹 出 自 己 的 参 数<br />
在 谓 词 名 前 的 一 个 下 划 线 (_)<br />
不 做 谓 词 名 的 大 小 写 转 换<br />
apicall 调 用 约 定 使 用 与 stdcall 一 样 的 参 数 和 栈 处 理 规 则 , 但 为 了 方 便 MS Windows API 函 数 的 调<br />
用 使 用 了 大 多 数 MS Windows API 函 数 调 用 所 用 的 命 名 约 定 。 根 据 该 约 定 , 谓 词 的 链 接 名 构 造 方 法 如 下 :<br />
• 在 谓 词 名 前 加 下 划 线 (_);<br />
• 谓 词 名 的 首 字 母 改 为 大 写 ;<br />
• 如 果 参 数 或 返 回 类 型 是 ANSI 的 , 加 后 缀 “A”, 如 果 是 Unicode 的 , 加 后 缀 “W”, 中 性 谓 词<br />
什 么 都 不 加 ;<br />
• 加 “@” 后 缀 ;<br />
• 后 面 附 加 推 入 栈 中 的 字 节 数 。<br />
例<br />
predicates<br />
predicateName : (integer, string) language apicall<br />
这 个 谓 词 的 参 数 类 型 表 明 它 是 一 个 Unicode 谓 词 ( 因 为 string 是 Unicode 串 域 的 )。 一 个 integer 和 一<br />
个 string 各 占 调 用 栈 的 4 字 节 , 因 而 , 它 的 链 接 名 就 是 :<br />
_PredicateNameW@8<br />
如 果 apicall 与 “as” 构 造 一 并 使 用 , 在 “as” 构 造 中 说 明 的 名 称 使 用 与 上 面 相 同 的 方 法 。<br />
apicall 只 能 直 接 使 用 在 谓 词 声 明 中 , 不 能 用 在 谓 词 域 定 义 中 。 谓 词 域 定 义 中 必 须 替 代 使 用 stdcall。<br />
下 表 比 较 了 c、apicall 及 stdcall 调 用 约 定 的 实 现 (prolog 调 用 约 定 有 特 殊 的 实 现 , 这 里 没 有 讨 论 ):<br />
类 型 清 栈 职 责 谓 词 名 大 小 写 转 换 链 接 名 构 造 方 法<br />
c 调 用 谓 词 从 栈 中 弹 出 参 数 不 转 换 谓 词 名 前 加 下 划 线 (_)<br />
stdcall 被 调 用 谓 词 从 栈 中 弹 出 自 己 不 转 换<br />
谓 词 名 前 加 下 划 线 (_)<br />
的 参 数<br />
apicall 被 调 用 谓 词 从 栈 中 弹 出 自 己<br />
的 参 数<br />
谓 词 名 首 字 母 转 换<br />
为 大 写<br />
谓 词 名 前 加 下 划 线 (_), 首 字 母 换 为<br />
大 写 , 加 “A” 或 “W” 后 缀 , 加 “@”<br />
后 缀 , 加 参 数 字 节 数 ( 十 进 制 )<br />
38
Visaul <strong>Prolog</strong> 谓 词 域 的 概 念 覆 盖 了 类 和 对 象 的 成 员 。 类 成 员 的 处 理 是 直 接 向 前 的 , 但 对 象 成 员 的 处<br />
理 需 要 注 意 。 对 象 谓 词 的 调 用 将 “ 回 退 ” 到 拥 有 该 成 员 的 对 象 关 联 中 。<br />
例<br />
设 有 如 下 声 明 :<br />
interface actionEventSource<br />
domains<br />
actionListener = (actionEventSource Source) procedure (i).<br />
predicates<br />
addActionListener : (actionListener Listener) procedure (i).<br />
...<br />
end interface<br />
再 假 设 有 一 个 button_class 类 支 持 actionEventSource。 点 击 按 钮 时 传 递 事 件 。 在<br />
myDialog_class 类 中 实 现 一 个 对 话 框 , 创 建 一 个 按 钮 并 监 听 它 的 动 作 事 件 以 作 出 反 应 :<br />
implement myDialog_class<br />
clauses<br />
new() :-<br />
OkButton = button_class::new(...),<br />
OkButton:addActionListener(onOk),<br />
...<br />
facts<br />
okPressed : () determ.<br />
predicates<br />
onOk : actionListener.<br />
clauses<br />
onOk(Source) :-<br />
assert(okPressed()).<br />
end implement<br />
在 这 个 例 子 中 重 要 的 是 onOk 是 一 个 对 象 成 员 , 而 且 , 当 按 了 按 钮 后 , 注 册 了 的 onOk 的 调 用 会 将 我<br />
们 带 回 给 拥 有 onOk 的 对 象 。 也 就 是 说 , 我 们 能 访 问 对 象 事 实 okPressed, 这 样 我 们 才 能 插 入 事 实 。<br />
Format Strings( 格 式 串 )<br />
对 谓 词 的 格 式 参 数 , 可 以 用 formatstring 属 性 标 记 成 格 式 串 。 格 式 串 中 可 以 有 原 态 字 符 , 这 样 的 字<br />
符 是 不 加 修 饰 地 原 样 打 印 的 , 还 有 以 百 分 号 (%) 开 头 的 格 式 域 。 如 果 % 后 面 的 是 未 知 字 符 ( 不 是 格 式 符 ),<br />
则 百 分 号 和 这 个 字 符 也 会 原 样 打 印 。<br />
例<br />
predicates<br />
writef : (string Format [formatstring], ...) procedure (i,...).<br />
格 式 域 的 构 成 是 :<br />
[-][0][width][.precision][type]<br />
上 述 所 有 组 份 都 是 可 选 的 。<br />
连 字 符 [-] 表 示 这 个 域 是 右 对 齐 的 ; 缺 省 是 左 对 齐 。 如 果 宽 度 值 [width] 没 有 设 置 , 或 是 实 际 字 符 数 比<br />
宽 度 值 还 要 大 , 则 没 有 效 果 。<br />
宽 度 前 的 零 [0] 表 示 对 值 要 添 加 零 直 到 达 到 最 小 宽 度 。 如 果 零 和 连 字 符 一 同 出 现 , 零 就 被 忽 略 了 。<br />
39
宽 度 [width] 是 正 的 十 进 制 数 , 表 示 域 段 的 最 小 宽 度 。 如 果 实 际 字 符 数 小 于 这 个 值 , 就 要 在 值 的 前 面<br />
( 若 设 置 了 ‘-’ 则 是 在 后 面 ) 添 加 空 格 字 符 。 如 果 实 际 字 符 数 比 这 个 值 大 , 就 没 有 什 么 改 变 。<br />
点 之 后 带 无 符 号 十 进 制 数 [.precision] 表 示 浮 点 数 精 度 , 也 可 以 表 示 从 一 个 串 里 最 多 打 印 出 的 字 符 数 。<br />
[type] 规 定 了 缺 省 之 外 其 它 一 些 格 式 。 如 , 在 该 域 可 以 用 一 个 规 定 符 表 示 一 个 整 数 要 格 式 化 为 一 个 无<br />
符 号 数 。 可 用 值 为 :<br />
f 将 实 数 格 式 化 为 定 点 十 进 制 数 , 如 123.4,0.004321。 这 是 实 数 的 缺 省 格 式 。<br />
e 将 实 数 格 式 化 为 指 数 表 示 法 , 如 1.234e+002,4.321e-003。<br />
g 将 实 数 格 式 化 为 f 和 e 格 式 中 较 短 的 那 种 , 但 当 指 数 值 小 于 -4 或 大 于 等 于 精 度 时 总 是 用 e 格<br />
式 。 尾 零 都 要 被 截 去 。<br />
d 或 D 格 式 化 为 有 符 号 十 进 制 数 。<br />
u 或 U 格 式 化 为 无 符 号 整 数 。<br />
x 或 X 格 式 化 为 十 六 进 制 数 。<br />
o 或 O 格 式 化 为 八 进 制 数 。<br />
c 格 式 化 为 一 个 字 符 。<br />
B 格 式 化 为 <strong>Visual</strong> <strong>Prolog</strong> 的 二 进 制 类 型 。<br />
R 格 式 化 为 数 据 库 索 引 数 。<br />
P 格 式 化 为 过 程 参 量 。<br />
s 格 式 化 为 串 。<br />
Integral Domains( 整 数 域 )<br />
整 数 域 用 于 表 示 整 数 , 它 分 成 两 个 主 要 类 型 : 有 符 号 数 和 无 符 号 数 。 整 数 域 也 有 不 同 的 表 示 范 围 , 预<br />
定 义 的 域 integer 和 unsigned 表 示 有 符 号 的 和 无 符 号 的 整 数 , 是 处 理 器 架 构 ( 如 32 位 机 器 上 的 32 位 , 等 )<br />
的 固 定 表 示 长 度 。<br />
IntegralDomain:<br />
DomainName-opt IntegralDomainProperties<br />
如 果 在 IntegralDomainPropertie 前 面 有 DomainName, 那 么 它 本 身 必 须 是 整 数 域 的 , 接 下<br />
来 的 域 是 这 个 域 的 一 个 子 类 型 。 此 时 ,IntegralDomainProperties 不 能 违 反 作 为 一 个 子 类 型 的 可 能<br />
性 , 也 就 是 说 , 数 值 表 示 不 能 超 范 围 , 不 能 改 变 比 特 位 数 。<br />
IntegralDomainProperties:<br />
IntegralSizeDescription IntegralRangeDescription-opt<br />
IntegralRangeDescription IntegralSizeDescription-opt<br />
IntegralSizeDescription:<br />
bitsize DomainSize<br />
DomainSize:<br />
IntegralConstantExpression<br />
IntegralSizeDescription( 整 数 尺 度 描 述 ) 说 明 该 整 数 域 的 DomainSize 大 小 , 以 比 特 为 单 位 。 编<br />
译 器 会 以 不 小 于 这 个 规 定 的 比 特 位 数 实 现 这 个 整 数 域 。DomainSize 的 值 应 该 是 正 数 并 且 不 能 超 过 编 译<br />
器 支 持 的 最 大 值 ( 对 v 6.x 来 说 是 32 位 )。 如 果 省 略 了 整 数 尺 度 描 述 , 就 使 用 和 父 域 一 样 的 尺 度 。 如 果 没<br />
有 父 域 , 则 使 用 处 理 器 的 本 身 的 尺 度 。<br />
IntegralRangeDescription:<br />
40
[ MinimalBoundary-opt .. MaximalBoundary-opt ]<br />
MinimalBoundary:<br />
IntegralConstantExpression<br />
MaximalBoundary:<br />
IntegralConstantExpression<br />
IntegralRangeDescription( 整 数 界 限 描 述 ) 说 明 该 整 数 域 最 小 值 MinimalBoundary 和 最 大 值<br />
MaximalBoundary。 如 果 省 略 了 , 就 使 用 父 域 的 界 限 。 如 果 没 有 父 域 , 就 使 用 DomainSize 来 确 定<br />
相 应 的 最 小 值 和 最 大 值 。<br />
注 意 , 最 小 值 不 能 大 于 最 大 值 , 也 就 是 :<br />
MinimalBoundary
这 里 的 RealConstantExpression 是 一 个 表 达 式 , 在 编 译 时 它 被 计 算 出 一 个 浮 点 值 。 也 就 是 说 ,<br />
在 编 译 时 该 实 数 域 的 精 度 和 界 限 必 须 是 可 计 算 的 。<br />
RealRangeDescription( 实 数 界 限 描 述 ) 说 明 该 实 数 域 最 小 值 和 最 大 值 。 如 果 省 略 了 , 就 使 用 父 域<br />
的 界 限 。 如 果 没 有 父 域 , 就 使 用 最 大 可 用 精 度 。<br />
注 意 , 最 小 值 不 能 大 于 最 大 值 , 也 就 是 :<br />
MinimalBoundary
常 数<br />
Constants 段<br />
constants 段 在 当 前 范 围 内 定 义 一 组 常 数 。<br />
常 数 定 义<br />
ConstantsSection :<br />
constants ConstantDefinition-dot-term-list-opt<br />
常 数 定 义 规 定 命 名 了 的 常 数 , 它 的 类 型 , 它 的 值 。<br />
ConstantDefinition: one of<br />
ConstantName = ConstantValue<br />
ConstantName : TypeName = ConstantValue<br />
ConstantName:<br />
LowerCaseIdentifier<br />
ConstantValue 应 该 为 表 达 式 , 在 编 译 时 应 该 能 计 算 得 到 值 并 且 具 有 相 应 域 的 类 型 。<br />
ConstantName 应 该 是 小 写 标 识 。<br />
只 有 对 下 列 内 建 的 域 才 可 以 省 略 类 型 名 :<br />
1. 数 值 ( 即 整 数 或 实 数 ) 常 数 。 在 这 种 情 况 下 , 对 常 数 使 用 相 应 匿 名 数 字 域 ( 详 细 请 参 见 数 字 域 )。<br />
2. 二 进 制 常 数 。<br />
3. 串 常 数 。<br />
4. 字 符 常 数 。<br />
例<br />
constants<br />
my_char = 'a'.<br />
true_const : boolean = true.<br />
binaryFileName = "mybin".<br />
myBinary = #bininclude(binaryFileName).<br />
Predicates( 谓 词 )<br />
Predicates 段<br />
谓 词 段 在 当 前 范 围 内 声 明 一 组 对 象 或 类 谓 词 。<br />
PredicatesSection :<br />
class-opt predicates PredicateDeclaration-dot-term-list-opt<br />
关 键 字 class 只 能 用 在 类 实 现 中 。 对 于 谓 词 , 在 接 口 中 声 明 的 总 是 对 象 谓 词 , 而 在 类 声 明 中 声 明 的 ,<br />
总 是 类 谓 词 。<br />
43
Predicate Declarations( 谓 词 声 明 )<br />
谓 词 声 明 用 于 在 一 个 范 围 内 声 明 谓 词 , 在 这 个 范 围 内 , 该 谓 词 是 可 见 的 。 当 谓 词 在 接 口 定 义 中 声 明 时 ,<br />
就 意 味 着 相 应 类 型 的 对 象 必 须 支 持 这 些 谓 词 。 当 谓 词 在 类 声 明 中 声 明 时 , 就 意 味 着 该 类 公 有 地 支 持 所 声 明<br />
的 谓 词 。 而 如 果 谓 词 是 在 类 实 现 中 声 明 的 , 则 意 味 着 谓 词 是 局 部 的 。 不 管 在 哪 种 情 况 下 , 必 须 有 谓 词 的 相<br />
应 定 义 。<br />
PredicateDeclaration :<br />
PredicateName : PredicateDomain LinkName-opt<br />
PredicateName : PredicateDomainName LinkName-opt<br />
LinkName :<br />
as StringLiteral<br />
PredicateName :<br />
LowerCaseIdentifier<br />
这 里 ,predicateDomainName( 谓 词 域 名 ) 是 在 域 段 中 声 明 的 谓 词 域 的 名 称 。<br />
谓 词 声 明 规 定 了 谓 词 的 名 称 、 它 的 类 型 、 模 式 、 流 ( 参 见 谓 词 域 ) 及 可 选 的 链 接 名 。<br />
只 有 类 谓 词 才 可 以 有 链 接 名 , 如 果 没 有 说 明 链 接 名 则 会 依 据 调 用 约 定 由 谓 词 名 产 生 相 应 的 链 接 名 。 如<br />
果 调 用 约 定 是 apicall, 则 这 个 链 接 名 还 要 由 as 子 句 加 工 。 如 果 不 做 这 个 加 工 , 就 使 用 替 代 的 stdcall 调 用<br />
约 定 。<br />
链 接 名 的 缀 饰 加 工<br />
有 时 链 接 名 必 须 有 _...@N 的 缀 饰 , 但 apicall 来 的 缺 省 名 则 是 错 的 。 在 这 样 的 缀 饰 中 , 后 缀 的 A 和 后 缀<br />
的 W 可 以 用 于 控 制 缀 饰 加 工 :<br />
predicates<br />
myPredicate : (string X) language stdcall as decorated.<br />
在 这 种 情 况 下 , 链 接 名 会 是 “_MyPredicate@4”, 而 apicall 会 使 它 成 为 “_MyPredicateW@4”。<br />
predicates<br />
myPredicate : (string X) language stdcall as decoratedA.<br />
在 这 种 情 况 下 , 链 接 名 会 是 “_MyPredicateA@4”, 而 apicall 会 使 它 成 为 “_MyPredicate@4”。<br />
predicates<br />
myPredicate : (string X) language stdcall as decoratedW.<br />
在 这 种 情 况 下 , 链 接 名 会 是 “_MyPredicateW@4”, 而 apicall 会 使 它 成 为 “_MyPredicate@4”。<br />
上 述 所 有 情 况 中 , 都 是 把 名 称 由 xxxx 变 为 _Xxxx, 并 加 上 后 缀 @N。 第 一 种 情 况 不 用 后 缀 的 字 母 , 第<br />
二 种 情 况 总 是 后 缀 A, 而 第 三 种 情 况 总 是 后 缀 W。 这 就 是 说 , 编 程 者 负 责 确 定 使 用 需 要 的 后 缀 , 不 过 不 需<br />
要 操 心 计 算 参 数 的 字 节 数 和 起 始 的 “_X”( 加 下 划 线 和 把 首 字 母 改 为 大 写 )。<br />
Constructors 段<br />
constructors 段 声 明 一 组 构 造 器 。 构 造 器 属 于 constructors 段 所 在 的 范 围 ( 参 见 类 声 明 和 类 实<br />
44
现 )。<br />
ConstructorsSection :<br />
constructors ConstructorDeclaration-dot-term-list-opt<br />
构 造 器 段 只 能 在 构 造 对 象 的 类 的 声 明 和 实 现 中 出 现 。<br />
Constructor 声 明<br />
构 造 器 声 明 说 明 类 的 命 名 了 的 构 造 器 。<br />
一 个 构 造 器 实 际 上 有 两 个 相 关 的 谓 词 :<br />
• 一 个 类 函 数 , 这 个 函 数 能 返 回 一 个 新 构 造 的 对 象 ,<br />
• 一 个 对 象 谓 词 , 该 谓 词 用 来 初 始 化 继 承 的 对 象 。<br />
相 关 的 构 造 器 对 象 谓 词 用 于 进 行 对 象 的 初 始 化 。 这 个 谓 词 只 能 在 该 类 本 身 由 该 构 造 器 调 用 , 或 是 由 继<br />
承 这 个 类 的 一 个 类 的 构 造 器 调 用 ( 即 基 类 初 始 化 )。<br />
ConstructorDeclaration :<br />
ConstructorName : PredicateDomain<br />
不 能 对 构 造 器 说 明 谓 词 模 式 , 构 造 器 总 是 procedure 模 式 的 。<br />
例 看 一 下 如 下 的 类 :<br />
class test_class : test<br />
constructors<br />
new : (integer Argument).<br />
end class test_class<br />
相 关 的 类 谓 词 有 如 下 特 征 :<br />
class predicates<br />
new : (integer) -> test.<br />
而 相 关 的 对 象 谓 词 特 征 如 下 :<br />
predicates<br />
new : (integer).<br />
再 来 看 一 下 如 下 的 实 现 :<br />
implement test2_class inherits test_class<br />
clauses<br />
new() :-<br />
test_class::new(7),<br />
% 在 "This" 上 调 用 基 类 构 造 器<br />
p(test_class::new(8)). % 创 建 基 类 一 个 新 对 象 并 把 它 传 递 给 p(...)<br />
...<br />
对 test_class::new 的 第 一 个 调 用 并 不 返 回 一 个 值 , 因 此 它 是 一 个 对 构 造 器 的 非 函 数 对 象 版 本 的 调<br />
用 , 也 就 是 说 , 它 是 在 This 上 的 基 类 构 造 器 的 一 个 调 用 。<br />
而 第 二 个 调 用 则 确 实 返 回 一 个 值 , 因 此 它 是 对 构 造 器 类 函 数 版 本 的 一 个 调 用 , 也 就 是 说 , 它 创 建 一 个<br />
新 的 对 象 。<br />
45
Predicates from Interface( 来 自 接 口 的 谓 词 )<br />
一 个 接 口 可 以 支 持 其 它 接 口 的 一 个 子 集 , 这 是 通 过 在 谓 词 from 段 声 明 谓 词 实 现 的 。predicates<br />
from 段 列 出 接 口 及 所 有 支 持 的 谓 词 。 对 谓 词 的 说 明 可 以 是 谓 词 的 名 称 或 名 称 加 元 维 。<br />
一 个 接 口 支 持 另 外 接 口 的 子 集 时 , 它 既 不 是 这 个 另 外 的 接 口 的 子 类 , 也 不 是 它 的 超 类 。<br />
对 predicates from 段 来 说 , 重 要 的 一 点 是 : 所 有 列 出 的 谓 词 都 保 留 在 原 来 的 接 口 中 , 因 此 :<br />
• 来 自 原 来 接 口 的 谓 词 不 会 有 支 持 冲 突 ;<br />
• 它 们 可 以 作 为 谓 词 由 原 来 的 接 口 中 继 承 。<br />
PredicatesFromInterface :<br />
predicates from InterfaceName PredicateNameWithArity-comma-sep-list-opt<br />
PredicatesFromInterface 只 能 用 在 接 口 定 义 中 。<br />
例<br />
interface aaa<br />
predicates<br />
ppp : ().<br />
qqq : ().<br />
end interface aaa<br />
interface bbb<br />
predicates from aaa<br />
ppp<br />
predicates<br />
rrr : ().<br />
end interface bbb<br />
interface ccc supports aaa, bbb<br />
end interface ccc<br />
尽 管 aaa 和 bbb 都 各 声 明 了 一 个 谓 词 ppp,ccc 还 是 可 以 无 冲 突 地 支 持 这 两 者 , 因 为 在 所 有 情 况 下<br />
ppp 都 有 aaa 作 为 源 接 口 。<br />
例<br />
interface aaa<br />
predicates<br />
ppp : ().<br />
qqq : ().<br />
end interface aaa<br />
interface bbb<br />
predicates from aaa<br />
ppp<br />
predicates<br />
rrr : ().<br />
end interface bbb<br />
class aaa_class : aaa<br />
end class aaa_class<br />
46
class bbb_class : bbb<br />
end class bbb_class<br />
implement aaa_class inherits bbb_class<br />
clauses<br />
qqq().<br />
end implement aaa_class<br />
aaa_class 可 以 由 bbb_class 类 继 承 ppp, 因 为 ppp 在 两 个 类 中 有 aaa 作 为 源 接 口 。<br />
Arity( 元 维 )<br />
一 个 谓 词 带 有 N 个 参 数 时 , 就 称 其 是 N 元 (N-ary) 的 , 或 说 元 维 是 N(arity N) 的 。 不 同 元 维 的 谓<br />
词 是 不 同 的 谓 词 , 即 使 它 们 的 名 称 相 同 也 是 这 样 。<br />
在 大 多 数 情 况 下 , 谓 词 的 元 维 是 清 楚 的 , 可 以 从 上 下 文 中 看 出 来 。 但 有 些 时 候 就 不 明 显 了 , 比 如 在 谓<br />
词 的 from 段 里 以 及 在 使 用 resolve 限 定 符 时 就 可 能 会 出 现 这 样 的 问 题 。<br />
为 了 能 够 区 分 谓 词 的 不 同 元 维 , 在 predicates from 段 里 及 使 用 resolve 限 定 符 时 , 可 以 选 用 谓 词<br />
名 称 加 元 维 的 方 法 来 说 明 。 可 以 使 用 如 下 的 方 法 :<br />
• Name/N 表 示 元 维 是 N 的 本 原 谓 词 Name( 即 不 是 一 个 函 数 ),<br />
• Name/N-> 表 示 元 维 是 N 的 函 数 Name,<br />
• Name/N... 表 示 带 有 N 个 参 数 后 跟 一 个 Ellipsis( 省 略 符 ) 参 数 ( 即 参 数 数 量 可 变 ) 的 本 原 谓<br />
词 Name。( 省 略 号 可 以 在 谓 词 及 谓 词 域 的 声 明 中 作 为 最 后 一 个 形 式 参 数 使 用 , 此 时 它 表 示 所 声<br />
明 的 谓 词 ( 谓 词 域 ) 有 可 变 数 量 的 参 数 。 省 略 流 必 须 与 省 略 参 数 相 匹 配 , 故 此 也 只 能 是 流 样 式 中<br />
的 最 后 一 个 流 。)<br />
• Name/N...-> 表 示 一 个 带 有 N 个 参 数 后 跟 一 个 省 略 参 数 的 函 数 Name。<br />
PredicateNameWithArity :<br />
PredicateName Arity-opt<br />
Arity : one of<br />
/ IntegerLiteral Ellipsis-opt<br />
/ IntegerLiteral Ellipsis-opt -><br />
在 Name/0... 和 Name/0...-> 的 情 况 中 , 零 是 可 以 省 去 的 , 因 而 也 可 以 分 别 写 成 Name/... 和<br />
Name/...->。<br />
Properties( 属 性 )<br />
属 性 段 声 明 在 当 前 范 围 内 对 象 或 类 的 属 性 。<br />
声 明<br />
PropertyDeclaration :<br />
PropertyName : PropertyType FlowPattern-list-opt.<br />
FlowPattern: one of<br />
(i)<br />
47
(o)<br />
属 性 的 声 明 类 似 于 single 事 实 。<br />
如 果 流 样 式 省 略 了 , 就 认 为 即 可 以 是 (i) 又 可 以 是 (o)。 例 如 :<br />
interface ip<br />
properties<br />
duration : integer.<br />
initialized : boolean.<br />
scale : string.<br />
end interface<br />
属 性 用 起 来 与 实 现 中 的 single 事 实 是 一 样 的 。 可 以 用 范 围 名 称 或 对 象 来 修 饰 限 制 属 性 。<br />
设 X 是 一 个 支 持 接 口 ip 的 对 象 :<br />
X:duration := 5,<br />
if X:initialized = true then ... else ... end if,<br />
X:scale := "meter",<br />
....<br />
在 ip 的 实 现 内 部 , 可 以 如 同 它 们 是 事 实 一 样 来 访 问 它 们 :<br />
duration := 5,<br />
if initialized = true then ... else ... end if,<br />
scale := "meter",<br />
....<br />
Implementation( 实 现 )<br />
属 性 是 通 过 定 义 一 个 获 取 值 的 函 数 及 一 个 适 当 的 设 置 值 的 谓 词 来 实 现 的 。<br />
如 :<br />
clauses<br />
duration() = duration_fact * scale.<br />
duration(D):- duration_fact := D/ scale.<br />
或 是 把 一 个 相 同 名 字 的 事 实 用 作 属 性 :<br />
facts<br />
initialized : boolean := false.<br />
不 能 让 设 置 和 获 取 谓 词 与 事 实 同 名 。 如 果 想 用 一 个 事 实 来 存 放 一 个 属 性 的 值 ( 我 们 经 常 这 样 做 ), 就<br />
必 须 给 事 实 另 一 个 名 字 , 如 :<br />
properties<br />
duration : integer.<br />
facts<br />
duration_fact : integer.<br />
clauses<br />
duration() = duration_fact.<br />
clauses<br />
duration(D) :-<br />
OldDuration = duration_fact,<br />
duration_fact := D,<br />
48
OldDuration D,<br />
!,<br />
sendChanged().<br />
duration(_D).<br />
不 能 把 duration 当 谓 词 ( 这 不 奇 怪 , 因 为 它 们 不 是 声 明 为 谓 词 而 是 声 明 为 属 性 的 ; 它 只 是 实 现 属 性 的<br />
存 和 取 的 方 法 的 )。 但 是 , 谓 词 的 名 称 它 占 用 了 , 所 以 不 能 用 duration\1 或 duration\0-> 再 声 明 谓 词 。<br />
实 现 的 细 节<br />
当 访 问 一 个 在 接 口 中 声 明 的 属 性 时 , 关 于 它 的 实 现 不 能 做 任 何 假 设 , 因 而 也 就 不 得 不 认 为 它 是 用 谓 词<br />
实 现 的 。 如 果 程 序 员 是 把 这 个 属 性 当 事 实 定 义 的 , 编 译 器 就 必 须 产 生 适 当 的 谓 词 , 当 通 过 一 个 接 口 来 访 问<br />
这 个 属 性 时 , 就 使 用 它 们 。 而 在 实 现 内 部 , 定 义 为 事 实 的 属 性 就 可 以 当 成 事 实 来 访 问 。<br />
限 制 读 写<br />
有 的 时 候 , 想 让 一 个 属 性 只 能 读 或 只 能 写 。 假 设 我 们 用 i/o 范 式 声 明 它 们 :<br />
duration : integer (o). % 一 个 只 读 的 属 性<br />
duration : integer (i). % 一 个 只 写 的 属 性<br />
duration : integer (o) (i). % 一 个 正 常 的 属 性 , 可 以 读 也 可 以 写 , 与 什 么 都 不 说 明 一 样<br />
duration : integer. % 与 上 面 声 明 的 一 样 。.<br />
如 果 属 性 声 明 为 只 读 , 就 可 以 只 声 明 取 (get) 谓 词 , 同 样 , 如 果 是 声 明 为 只 写 就 可 以 只 声 明 设 置 (set)<br />
谓 词 。<br />
当 然 , 如 果 属 性 是 当 成 事 实 来 实 现 的 , 在 实 现 内 部 就 可 以 把 它 当 成 一 个 普 通 的 事 实 来 使 用 。<br />
Properties from Interface( 来 自 接 口 的 属 性 )<br />
一 个 接 口 可 以 支 持 另 一 个 接 口 的 子 集 , 这 是 通 过 在 属 性 from 段 声 明 属 性 实 现 的 。properties from<br />
段 列 出 接 口 及 所 有 支 持 的 属 性 。<br />
一 个 接 口 支 持 另 外 接 口 的 子 集 时 , 它 既 不 是 这 个 另 外 的 接 口 的 子 类 , 也 不 是 它 的 超 类 。<br />
对 properties from 段 来 说 , 重 要 的 一 点 是 : 所 有 列 出 的 属 性 都 保 留 在 原 来 的 接 口 中 , 因 此 :<br />
• 它 们 可 以 作 为 属 性 由 原 来 的 接 口 中 继 承 。<br />
PropertiesFromInterface :<br />
properties from InterfaceName PpropertyName-comma-sep-list-opt<br />
PropertiesFromInterface 只 能 用 在 接 口 定 义 中 。<br />
例<br />
interface aaa<br />
properties<br />
pp : integer.<br />
qq : boolean.<br />
end interface aaa<br />
interface bbb<br />
properties from aaa<br />
49
pp<br />
properties<br />
rr : string.<br />
end interface bbb<br />
interface ccc supports aaa, bbb<br />
end interface ccc<br />
尽 管 aaa 和 bbb 都 各 声 明 了 一 个 属 性 ppp,ccc 还 是 可 以 无 冲 突 地 支 持 这 两 者 , 因 为 在 所 有 情 况 下<br />
ppp 都 有 aaa 作 为 源 接 口 。<br />
例<br />
interface aaa<br />
properties<br />
pp : integer.<br />
qq : boolean.<br />
end interface aaa<br />
interface bbb<br />
properties from aaa<br />
pp<br />
properties<br />
rr : string.<br />
end interface bbb<br />
class aaa_class : aaa<br />
end class aaa_class<br />
class bbb_class : bbb<br />
end class bbb_class<br />
implement aaa_class inherits bbb_class<br />
facts<br />
pp_fact(): integer.<br />
clauses<br />
pp()= pp_fact-3.<br />
clauses<br />
pp(D):- pp_fact:=D+3.<br />
end implement aaa_class<br />
aaa_class 可 以 由 bbb_class 类 继 承 pp, 因 为 pp 在 两 个 类 中 有 aaa 作 为 源 接 口 。<br />
Facts<br />
facts 段 声 明 一 个 事 实 数 据 库 , 它 是 由 一 些 事 实 构 成 的 。 事 实 数 据 库 和 事 实 是 属 于 当 前 范 围 的 。<br />
事 实 数 据 库 可 是 是 类 一 级 的 , 也 可 以 是 对 象 一 级 的 。<br />
事 实 数 据 库 只 能 在 类 实 现 中 声 明 。<br />
如 果 事 实 数 据 库 有 名 称 , 也 就 隐 含 地 附 加 定 义 了 一 个 复 合 域 。 这 个 域 具 有 与 事 实 段 相 同 的 名 称 , 并 具<br />
有 与 事 实 段 中 的 事 实 相 对 应 的 函 子 。<br />
如 果 facts 段 有 名 称 , 这 个 名 字 就 表 示 了 内 建 域 factDB 的 一 个 值 。save 和 consult 谓 词 可 以 接 纳 这<br />
50
个 域 的 值 。<br />
FactsSection :<br />
class-opt facts FactsSectionName-opt FactDeclaration-dot-term-list-opt<br />
FactsSectionName :<br />
- LowerCaseIdentifier<br />
Fact 声 明<br />
事 实 声 明 说 明 一 个 事 实 数 据 库 的 事 实 。 事 实 声 明 可 以 是 一 个 事 实 变 量 , 也 可 以 是 一 个 函 子 事 实 。<br />
FactDeclaration :<br />
FactVariableDeclaration<br />
FactFunctorDeclaration<br />
FactFunctorDeclaration :<br />
FactName : ( Argument-comma-sep-list-opt ) FfactMode-opt<br />
FactName :<br />
LowerCaseIdentifier<br />
事 实 函 子 的 声 明 , 缺 省 时 具 有 nondeterm 的 事 实 模 式 。<br />
事 实 函 子 可 以 经 子 句 段 初 始 化 。 这 种 情 况 下 , 子 句 中 的 值 应 该 是 表 达 式 , 在 编 译 时 应 能 得 到 确 切 的 值 。<br />
FactMode : one of<br />
determ nondeterm single<br />
如 果 模 式 是 single, 则 这 个 事 实 总 是 有 一 个 且 只 能 有 一 个 值 ,assert 谓 词 会 把 旧 值 以 新 值 替 代 掉 。<br />
谓 词 retract 不 适 用 于 single 事 实 。<br />
如 果 模 式 是 nondeterm, 则 该 事 实 可 以 有 0、1 或 任 意 个 值 。 如 果 模 式 是 determ, 则 事 实 只 能 有 0<br />
或 1 个 值 。 如 果 事 实 有 0 个 值 , 则 任 何 对 它 的 读 访 问 都 会 失 败 。<br />
事 实 变 量 的 声 明<br />
一 个 事 实 变 量 , 就 如 同 只 有 一 个 参 数 的 single 函 子 事 实 。 不 过 , 语 法 上 它 是 一 个 可 变 量 ( 即 可 以 赋 值 )。<br />
FactVariableDeclaration :<br />
FactVariableName : Domain InitialValue-opt<br />
InitialValue :<br />
:= ConstantValue<br />
:= erroneous<br />
FactVariableName :<br />
LowerCaseIdentifier<br />
常 数 值 ConstantValue 应 该 是 (Domain 类 型 的 ) 一 个 项 , 它 在 编 译 时 应 该 能 得 到 确 切 的 值 。<br />
只 有 当 事 实 变 量 在 一 个 构 造 器 里 被 初 始 化 时 , 常 数 值 才 可 以 省 去 。<br />
类 事 实 变 量 总 是 要 有 初 始 常 数 值 。<br />
注 意 , 关 键 字 erroneous 可 以 当 作 一 个 值 赋 给 一 个 事 实 变 量 。 下 面 两 种 情 况 都 是 允 许 的 :<br />
51
facts<br />
thisWin : vpiDomains::windowHandle := erroneous.<br />
clauses<br />
p() :- thisWin := erroneous.<br />
赋 值 成 erroneous, 是 想 要 在 发 生 了 代 码 错 误 地 使 用 了 没 有 初 始 化 的 事 实 变 量 时 , 给 出 明 确 的 运 行<br />
时 错 误 。<br />
Facts<br />
事 实 只 能 在 一 个 类 的 实 现 中 声 明 , 因 而 , 也 只 能 在 这 个 实 现 中 引 用 。 因 此 , 事 实 的 范 围 是 它 的 声 明 所<br />
在 的 实 现 。 但 是 , 对 象 事 实 的 生 命 期 是 它 所 属 的 对 象 的 生 命 期 , 同 样 , 类 事 实 的 生 命 期 是 从 程 序 的 开 始 一<br />
直 到 程 序 结 束 。<br />
例 下 面 的 类 声 明 了 一 个 对 象 事 实 objectFact 和 一 个 类 事 实 classFact:<br />
implement aaa_class<br />
facts<br />
objectFact : (integer Value) determ.<br />
class facts<br />
classFact : (integer Value) determ.<br />
...<br />
end implement aaa_class<br />
Clauses( 子 句 )<br />
Clauses 段<br />
clauses 段 由 一 些 子 句 构 成 , 它 包 含 了 谓 词 的 实 现 或 事 实 的 初 始 化 值 。<br />
一 个 子 句 段 可 以 包 含 多 个 谓 词 及 事 实 的 子 句 。 另 一 方 面 , 一 个 ( 相 同 名 称 及 元 维 ) 谓 词 / 事 实 的 所 有<br />
子 句 在 一 个 子 句 段 中 必 须 集 中 在 一 起 , 不 能 间 隔 有 别 的 谓 词 / 事 实 的 子 句 。<br />
Clauses<br />
ClausesSection :<br />
clauses Clause-dot-term-list-opt<br />
子 句 用 于 定 义 谓 词 。 一 个 谓 词 由 一 组 子 句 来 定 义 , 每 个 子 句 依 次 执 行 , 直 到 它 们 中 的 一 个 成 功<br />
(succeeds), 或 是 直 到 再 也 没 有 其 它 剩 下 的 子 句 。 如 果 没 有 子 句 成 功 , 那 么 这 个 谓 词 就 失 败 (fails)<br />
了 。<br />
如 果 一 个 子 句 成 功 了 , 而 此 时 在 该 谓 词 中 还 剩 有 其 它 相 关 的 子 句 , 程 序 控 制 就 可 以 在 后 面 再 回 溯<br />
(backtrack) 到 这 个 谓 词 的 这 些 子 句 上 以 寻 求 其 它 的 解 。 因 此 , 一 个 谓 词 可 以 失 败 , 可 以 成 功 , 甚 至<br />
可 以 成 功 多 次 。<br />
一 个 子 句 有 头 部 及 可 选 的 体 部 。<br />
当 一 个 谓 词 被 调 用 时 , 它 的 子 句 依 次 ( 从 上 到 下 ) 被 检 测 。 对 每 个 子 句 来 说 , 头 部 要 与 调 用 参 数 进 行<br />
合 一 , 如 果 合 一 成 功 , 有 体 部 时 才 执 行 体 部 。 只 有 在 头 部 和 体 部 都 成 功 时 , 子 句 才 成 功 , 否 则 就 失 败 了 。<br />
子 句 是 由 头 部 及 一 个 可 选 的 体 部 构 成 的 。<br />
52
Clause :<br />
ClauseHead ReturnValue-opt ClauseBody-opt .<br />
ClauseHead :<br />
LowercaseIdentifier ( Term-comma-sep-list-opt )<br />
ReturnValue :<br />
= Term<br />
ClauseBody :<br />
:- Term<br />
Goal Section( 目 标 段 )<br />
goal 段 是 程 序 的 入 口 。 程 序 开 始 时 就 从 goal 开 始 执 行 ,goal 执 行 完 , 程 序 就 退 出 了 。<br />
GoalSection :<br />
goal Term.<br />
goal 段 是 由 子 句 体 构 成 的 , 这 个 段 定 义 了 自 己 的 范 围 , 因 此 所 有 的 调 用 都 应 包 括 类 限 定 符 。<br />
通 常 , 目 标 必 须 是 procedure 模 式 的 。<br />
Terms 项<br />
本 节 描 述 项 以 及 项 和 子 句 的 执 行 / 计 算 是 如 何 进 行 的 。<br />
从 语 义 上 说 , 有 两 类 项 : 公 式 (formulas) 和 表 达 式 (expressions)。<br />
表 达 式 代 表 值 , 如 数 字 7。<br />
公 式 代 表 逻 辑 说 明 , 如 “ 数 字 7 大 于 数 字 3”。<br />
而 依 语 法 来 看 , 这 两 类 其 实 有 很 大 的 重 叠 , 因 此 语 法 上 把 这 两 类 合 并 成 项 (terms)。<br />
下 面 对 Term 的 定 义 是 简 化 了 的 , 因 为 按 它 包 含 的 语 法 构 造 来 讲 有 些 是 不 合 法 的 。 比 如 ,! + ! 就 是 不<br />
合 法 的 写 法 。 不 过 , 这 种 简 洁 的 语 法 描 述 与 对 语 言 概 念 、 类 型 系 统 及 下 面 描 述 的 算 子 层 次 的 直 觉 理 解 相 结<br />
合 , 还 是 非 常 有 用 的 。<br />
Term:<br />
( Term )<br />
Literal<br />
Variable<br />
Identifier<br />
MemberAccess<br />
PredicateCall<br />
PredicateExpression<br />
UnaryOperator Term<br />
Term BinaryOperator Term<br />
Cut<br />
Ellipsis<br />
FactvariableAssignment<br />
Backtracking( 回 溯 )<br />
53
<strong>Prolog</strong> 程 序 的 求 值 就 是 对 目 标 的 一 个 解 的 搜 寻 。 对 解 的 搜 索 的 每 一 步 都 有 可 能 成 功 或 失 败 。 程 序 执 行<br />
过 程 中 的 某 个 点 上 , 对 搜 索 解 会 有 多 种 可 能 , 在 这 种 选 择 点 上 就 会 创 建 一 个 回 溯 点 (backtrack point)。<br />
回 溯 点 是 一 种 记 录 , 它 包 含 有 程 序 的 状 态 及 还 未 执 行 的 选 择 的 指 针 。 如 果 先 前 的 一 个 选 择 没 有 能 够 得 到 解<br />
( 也 就 是 失 败 了 ), 程 序 就 会 回 溯 到 记 录 的 回 溯 点 上 来 , 因 而 可 以 恢 复 程 序 的 状 态 再 追 寻 其 它 的 选 择 。 后<br />
面 会 要 描 述 这 个 机 理 并 用 例 子 来 详 细 说 明 。<br />
Literals( 文 字 )<br />
文 字 具 有 通 用 类 型 。<br />
Literal:<br />
IntegerLiteral<br />
RealLiteral<br />
CharacterLiteral<br />
StringLiteral<br />
BinaryLiteral<br />
ListLiteral<br />
CompoundDomainLiteral<br />
参 看 词 汇 元 素 中 的 文 字 。<br />
Variables( 变 量 )<br />
<strong>Visual</strong> <strong>Prolog</strong> 中 的 变 量 其 实 是 不 可 变 的 : 一 经 绑 定 为 一 个 值 时 它 们 就 一 直 保 有 这 个 值 , 但 回 溯 可 以<br />
为 变 量 解 除 绑 定 以 恢 复 程 序 的 先 前 状 态 。<br />
一 个 变 量 ( 在 合 一 和 匹 配 时 ) 可 以 被 绑 定 , 如 果 已 经 被 绑 定 了 , 就 用 它 绑 定 的 值 进 行 解 算 。<br />
变 量 名 以 一 个 大 写 字 母 或 一 个 下 划 线 开 头 , 后 跟 字 母 ( 可 以 是 大 写 也 可 以 是 小 写 )、 数 字 和 下 划 线 序<br />
列 ( 称 为 大 写 标 识 ):<br />
Variable:<br />
UppercaseIdentifer<br />
下 面 这 些 都 是 合 法 的 变 量 名 :<br />
My_first_correct_variable_name<br />
_<br />
_Sales_10_11_86<br />
而 下 面 这 些 则 是 不 合 法 的 :<br />
1stattempt<br />
second_attempt<br />
名 字 是 一 个 下 划 线 ( 即 _) 的 变 量 称 为 匿 名 变 量 , 它 用 于 形 式 上 需 要 但 具 体 的 值 我 们 并 不 关 心 的 场<br />
合 。 每 次 出 现 的 匿 名 变 量 都 是 独 立 的 , 也 就 是 说 , 哪 怕 在 一 个 子 句 中 使 用 了 多 次 匿 名 变 量 , 它 们 之 间 也 是<br />
没 有 关 系 的 。<br />
名 字 用 一 个 下 划 线 开 头 的 变 量 并 不 是 匿 名 变 量 , 但 它 的 值 仍 是 我 们 不 关 心 而 忽 略 的 。 如 果 它 的 值 实 际<br />
上 没 有 被 忽 略 , 编 译 器 会 给 出 一 个 警 告 。<br />
<strong>Prolog</strong> 的 变 量 是 局 限 于 它 所 在 的 子 句 的 , 即 : 如 果 两 个 子 句 都 含 有 变 量 X, 这 两 个 X 变 量 是 独 立 不 相<br />
关 的 。<br />
54
当 一 个 变 量 还 没 有 与 一 个 项 联 系 在 一 起 时 , 称 这 个 变 量 是 自 由 的 ; 而 当 它 与 一 个 项 合 一 后 , 则 称 其<br />
为 绑 定 的 或 实 例 化 了 的 。<br />
<strong>Visual</strong> <strong>Prolog</strong> 编 译 器 对 名 称 不 区 分 除 首 字 母 而 外 的 大 小 写 ,SourceCode 和 SOURCECODE 这 两<br />
个 变 量 名 指 的 是 同 一 个 变 量 。<br />
Identifier( 标 识 )<br />
Identifier:<br />
MemberName<br />
GlobalScopeMembername<br />
ScopeQualifiedMemberName<br />
MemberName:<br />
LowerCaseIdentifier<br />
标 识 用 于 指 称 命 名 了 的 实 体 ( 如 类 、 接 口 、 常 数 、 域 、 谓 词 、 事 实 , 等 等 )。<br />
标 识 只 能 是 小 写 标 识 ( 也 就 是 一 个 小 写 字 母 后 跟 字 母 、 数 字 和 下 划 线 字 符 等 的 序 列 )。<br />
许 多 实 体 可 以 有 相 同 的 名 称 , 因 此 , 可 能 需 要 限 定 小 写 标 识 名 的 特 定 的 影 响 范 围 , 或 说 明 名 称 是 全 局<br />
的 。<br />
例 下 面 这 些 是 无 限 定 的 标 识 :<br />
全 局 实 体 的 访 问<br />
integer<br />
mainExe<br />
myPredicate<br />
在 <strong>Visual</strong> <strong>Prolog</strong> 中 , 全 局 实 体 只 有 内 建 的 域 、 谓 词 和 常 数 。 全 局 名 称 在 任 何 范 围 内 都 是 可 以 直 接 访<br />
问 的 , 但 也 存 在 全 局 名 称 被 一 个 局 部 名 称 或 引 入 名 称 屏 蔽 的 情 况 。 此 时 , 全 局 实 体 可 以 用 一 个 双 冒 号 “::”<br />
( 不 需 要 前 缀 类 / 接 口 名 称 ) 来 修 饰 。 双 冒 号 可 以 用 在 任 何 地 方 , 但 最 重 要 的 使 用 场 合 是 接 口 名 称 用 于 形 式 参<br />
数 类 型 说 明 符 时 。<br />
GlobalScopeMemberName:<br />
:: MemberName<br />
例 内 建 域 是 定 义 为 全 局 范 围 的 , 为 避 免 含 糊 或 强 调 这 个 特 殊 的 域 , 也 可 以 使 用 其 全 局 范 围 成 员 名 称 :<br />
::integer<br />
类 / 接 口 成 员 的 访 问<br />
类 与 接 口 的 静 态 成 员 的 访 问 是 通 过 带 类 名 称 ( 及 可 选 的 名 称 范 围 前 缀 ) 的 限 定 符 进 行 的 :<br />
ScopeQualifiedMemberName<br />
NamespacePrefix-opt ScopeName :: MemberName<br />
NamespacePrefix:<br />
NamespaceIdentifier-opt \<br />
ScopeName:<br />
LowercaseIdentifier<br />
55
ScopeName 是 定 义 / 声 明 该 名 称 的 类 或 接 口 的 名 字 。<br />
Namespace 的 前 缀 在 Referencing names in namespaces 中 说 明 。<br />
有 些 名 称 的 访 问 可 以 不 要 限 定 符 , 参 看 范 围 与 可 见 性 。<br />
Predicate Call( 谓 词 调 用 )<br />
谓 词 调 用 的 形 式 是 :<br />
PredicateCall:<br />
Term ( Term-comma-sep-list-opt )<br />
第 一 项 必 须 是 一 个 可 以 求 得 谓 词 类 型 的 值 的 表 达 式 。 通 常 , 它 是 一 个 类 中 一 个 谓 词 的 名 称 , 或 是 对 一<br />
个 对 象 的 谓 词 成 员 求 值 的 表 达 式 。<br />
要 注 意 , 有 的 谓 词 是 返 回 值 的 , 而 有 些 则 不 会 返 回 值 。 返 回 值 的 谓 词 是 一 个 表 达 式 , 这 样 的 谓 词 调 用<br />
常 称 为 一 个 函 数 调 用 。 常 规 地 , 谓 词 是 返 回 值 的 。<br />
谓 词 的 调 用 是 通 过 应 用 参 数 于 该 谓 词 来 进 行 的 。 谓 词 必 须 具 有 与 参 数 自 由 / 绑 定 状 态 相 匹 配 的 流 样 式 。<br />
大 多 数 谓 词 是 由 一 组 子 句 定 义 的 , 但 有 的 谓 词 是 由 语 言 内 建 的 , 还 有 的 是 在 外 部 的 DLL 中 定 义 的 ( 可<br />
能 还 是 另 外 的 编 程 语 言 )。<br />
当 调 用 谓 词 时 , 各 个 子 句 依 次 执 行 直 到 其 中 的 一 个 成 功 , 或 是 再 没 有 可 执 行 的 子 句 。 如 果 没 有 子 句 成<br />
功 则 谓 词 就 失 败 了 。<br />
如 果 一 个 子 句 成 功 了 而 还 剩 有 子 句 , 就 会 有 一 个 回 溯 点 创 建 在 下 一 个 相 关 的 子 句 上 。<br />
这 样 , 谓 词 可 以 失 败 , 成 功 , 甚 至 成 功 多 次 。<br />
每 个 子 句 有 头 部 及 可 选 的 体 部 。<br />
调 用 谓 词 时 , 子 句 被 依 次 ( 从 上 到 下 ) 求 值 。 每 个 子 句 在 头 部 的 参 数 与 调 用 的 参 数 进 行 合 一 。 如 果 合<br />
一 成 功 , 有 体 部 时 才 会 执 行 体 部 。 只 有 头 部 成 功 且 体 部 也 成 功 , 子 句 才 成 功 , 否 则 就 失 败 了 。<br />
例<br />
clauses<br />
ppp() :- qqq(X), write(X), fail.<br />
qqq(1).<br />
qqq(2).<br />
qqq(3).<br />
调 用 ppp 时 它 接 着 会 调 用 qqq。 当 qqq 被 调 用 时 , 它 首 先 在 第 二 个 子 句 上 创 建 一 个 回 溯 点 , 然 后 执 行<br />
第 一 个 子 句 。 这 时 ppp 中 的 自 由 变 量 X 与 数 字 1 匹 配 , 这 样 就 将 X 绑 定 为 1。<br />
接 着 ,ppp 的 X( 也 就 是 1) 被 写 出 , 然 后 fail 导 致 回 溯 到 回 溯 点 。 因 而 程 序 控 制 会 转 到 qqq 的 第 二 个<br />
子 句 , 而 程 序 的 状 态 也 会 回 到 第 一 次 进 入 qqq 时 的 状 态 , 即 ppp 中 的 X 又 是 未 绑 定 的 了 。<br />
在 实 际 执 行 qqq 中 的 第 二 个 子 句 之 前 , 会 先 在 第 三 个 子 句 上 创 建 一 个 回 溯 点 。 接 下 来 的 过 程 与 1 的 一<br />
样 。<br />
Unification( 合 一 )<br />
当 调 用 一 个 谓 词 时 , 调 用 的 参 数 会 与 各 子 句 的 头 部 中 的 项 进 行 合 一 。<br />
所 谓 合 一 , 就 是 变 量 绑 定 的 过 程 , 它 使 两 个 项 相 等 , 并 且 尽 量 少 做 绑 定 ( 也 就 是 尽 可 能 多 地 留 下 以 后<br />
绑 定 的 余 地 )。<br />
56
变 量 可 以 绑 定 于 任 何 种 类 的 项 , 包 括 变 量 或 含 有 变 量 的 项 。 而 合 一 可 以 是 可 能 的 , 也 可 以 是 不 可 能 的 ,<br />
也 就 是 说 , 可 以 成 功 , 或 是 失 败 。<br />
变 量 及 其 要 绑 定 的 项 是 有 类 型 的 , 一 个 变 量 只 能 和 与 它 同 类 型 的 或 是 其 子 类 型 的 项 做 绑 定 。 如 果 两 个<br />
变 量 是 互 相 绑 定 的 , 则 它 们 必 须 是 相 同 的 类 型 。<br />
合 一 出 现 在 一 个 谓 词 调 用 和 子 句 的 头 部 间 。 当 两 个 项 进 行 相 等 比 较 时 也 会 出 现 合 一 。<br />
例 考 虑 两 个 项 ( 同 一 类 型 的 ):<br />
T1 = f1(g(), X, 17, Y, 17)<br />
T2 = f1(Z, Z, V, U, 43)<br />
我 们 来 试 试 把 这 两 个 项 从 左 到 右 进 行 合 一 。T1 和 T2 都 是 f1/5 项 , 是 匹 配 的 。 因 此 , 我 们 来 试 着 由 T1<br />
的 参 数 合 一 T2 相 应 的 参 数 。 首 先 要 合 一 Z 和 g(), 这 只 要 把 Z 绑 定 为 g() 就 可 以 了 。 目 前 为 止 还 不 错 , 我 们<br />
得 到 了 第 一 个 绑 定 :<br />
Z = g()<br />
接 下 来 第 二 个 参 数 是 X 和 Z, 而 后 者 已 经 绑 定 为 g() 了 。 只 要 让 X 绑 定 为 g(), 这 两 个 参 数 也 是 可 以 合<br />
一 的 , 这 样 我 们 有 了 第 二 个 绑 定 :<br />
X = Z = g()<br />
再 接 下 来 , 必 须 把 V 绑 定 为 17, 还 要 把 Y 绑 定 为 U。 现 在 已 经 绑 定 的 有 :<br />
X = Z = g()<br />
V = 17<br />
Y = U<br />
两 个 合 一 的 项 现 在 等 价 于 下 面 的 项 :<br />
T1 = f1(g(), g(), 17, Y, 17)<br />
T2 = f1(g(), g(), 17, Y, 43)<br />
但 是 我 们 还 没 有 合 一 最 后 两 个 参 数 , 这 两 个 参 数 是 17 和 43。 没 有 什 么 变 量 绑 定 能 使 这 两 个 项 相 等 ,<br />
所 以 最 终 合 一 失 败 了 。T1 和 T2 不 能 合 一 。<br />
上 面 这 个 例 子 中 ,T1 可 以 是 一 个 谓 词 调 用 而 T2 可 以 是 一 个 子 句 的 头 部 。 当 然 , 它 们 也 可 以 是 两 个 用<br />
“=” 比 较 的 项 。<br />
Matching( 匹 配 )<br />
匹 配 只 有 一 点 与 合 一 不 同 , 这 就 是 匹 配 时 变 量 只 能 绑 定 于 根 基 (grounded) 项 。 所 谓 根 基 项 , 就 是<br />
不 含 任 何 未 绑 定 变 量 的 项 。<br />
正 是 说 明 谓 词 的 流 样 式 , 使 得 我 们 可 以 用 匹 配 而 不 用 全 面 的 合 一 成 为 可 能 。<br />
例<br />
clauses<br />
ppp(Z, Z, 17).<br />
qqq() :-<br />
ppp(g(), X, 17).<br />
57
调 用 ppp 时 合 一 ppp 的 子 句 , 只 要 使 用 下 面 的 绑 定 , 是 可 行 的 :<br />
Z = X = g()<br />
如 果 ppp 的 流 是 (i,o,i), 合 一 就 只 是 一 个 匹 配 :<br />
• g() 是 个 输 入 , 作 为 第 一 个 参 数 , 它 绑 定 于 Z,<br />
• 子 句 中 第 二 个 参 数 因 此 也 可 以 绑 定 并 可 以 输 出 给 X, 这 样 X 就 变 成 绑 定 于 g(),<br />
• 最 后 , 第 三 个 参 数 是 17, 它 是 一 个 输 入 , 这 个 数 只 是 简 单 地 与 子 句 中 的 第 三 个 参 数 作 比 较 。<br />
可 以 看 到 , 正 是 流 样 式 使 得 有 可 能 预 知 子 句 并 不 需 要 实 际 进 行 合 一 。<br />
嵌 套 的 函 数 调 用<br />
要 合 一 或 匹 配 的 项 可 以 包 含 子 项 , 而 子 项 是 表 达 式 或 函 数 调 用 , 它 们 需 要 在 合 一 / 匹 配 完 成 之 前 进 行<br />
求 值 。<br />
这 样 的 子 项 求 值 是 按 需 要 进 行 的 。<br />
在 谓 词 调 用 时 , 所 有 输 入 参 数 在 谓 词 调 用 前 做 求 值 , 所 有 输 出 参 数 是 变 量 , 不 需 要 求 值 。<br />
子 句 头 部 也 可 以 包 含 需 要 求 值 的 项 , 在 合 一 / 匹 配 前 确 定 下 来 。<br />
• 在 求 值 进 行 之 前 , 先 做 不 需 要 做 求 值 处 理 的 合 一 / 匹 配 ;<br />
• 然 后 相 应 于 输 入 的 参 数 从 左 到 右 逐 个 求 值 。 求 值 一 个 就 与 对 应 的 输 入 比 较 一 个 ;<br />
• 接 着 对 子 句 的 体 求 值 ;<br />
• 再 从 左 到 右 对 输 出 参 数 求 值 ;<br />
• 最 后 , 如 果 谓 词 是 函 数 , 就 对 返 回 值 求 值 。<br />
如 果 上 述 过 程 中 出 现 任 何 失 败 , 就 不 进 行 其 它 的 求 值 。<br />
总 之 , 基 本 原 则 是 :<br />
• 输 入 求 值 先 于 体 部 求 值 ;<br />
• 体 部 求 值 之 后 是 输 出 求 值 ;<br />
• 求 值 从 左 向 右 进 行 。<br />
匿 名 谓 词<br />
匿 名 谓 词 是 对 一 个 谓 词 的 值 进 行 计 算 的 表 达 式 , 这 个 值 可 以 绑 定 给 一 个 变 量 , 可 以 作 为 参 数 传 递 或 作<br />
为 结 果 返 回 , 但 这 个 值 没 有 任 何 类 、 接 口 或 实 现 的 名 称 。<br />
匿 名 谓 词 可 以 在 表 达 式 出 现 的 关 联 中 获 取 值 , 可 以 用 它 来 避 免 一 些 冗 长 难 懂 的 代 码 。<br />
语 法<br />
匿 名 谓 词 是 项 :<br />
Term : one of<br />
...<br />
AnonymousPredicate<br />
...<br />
匿 名 谓 词 是 一 个 在 大 括 号 中 的 无 名 子 句 , 某 些 部 分 是 可 选 的 , 形 式 如 下 :<br />
AnonymousPredicate : one of<br />
{ ( Arg-comma-sep-list ) = Term }<br />
58
{ ( Arg-comma-sep-list ) = Term :- Term }<br />
{ ( Arg-comma-sep-list ) :- Term }<br />
{ = Term }<br />
{ = Term :- Term }<br />
{ :- Term }<br />
省 略 参 数 表 意 味 着 “ 需 要 数 量 的 参 数 ”, 用 在 不 需 要 实 际 使 用 参 数 时 。<br />
语 义<br />
匿 名 谓 词 表 达 式 对 一 个 谓 词 求 值 。 看 下 面 的 代 码 :<br />
clauses<br />
run() :-<br />
Inc = { (X) = X+1 },<br />
A = Inc(4),<br />
B = Inc(23),<br />
stdio::writef("A = %, B = %", A, B).<br />
Inc 成 了 一 个 增 量 谓 词 , 程 序 的 结 果 是 :<br />
A = 5, B = 24<br />
上 面 的 代 码 相 当 于 这 样 :<br />
clauses<br />
run() :-<br />
Inc = inc,<br />
A = Inc(4),<br />
B = Inc(23),<br />
stdio::writef("A = %, B = %", A, B).<br />
class predicates<br />
inc : (integer X) -> integer R.<br />
clauses<br />
inc(X) = X+1.<br />
这 里 , 最 后 一 行 可 以 看 到 子 句 (X) = X+1, 在 这 里 它 是 一 个 命 名 了 的 谓 词 。<br />
在 匿 名 谓 词 之 外 ( 即 匿 名 谓 词 出 现 之 前 ) 绑 定 的 变 量 可 以 在 匿 名 谓 词 中 使 用 , 变 量 的 值 将 被 匿 名 谓 词<br />
获 取 。 而 在 匿 名 谓 词 中 绑 定 的 变 量 是 该 匿 名 谓 词 的 局 部 变 量 。<br />
获 取 关 联<br />
匿 名 谓 词 可 以 获 取 关 联 , 也 就 是 说 它 可 以 引 用 关 联 中 定 义 的 东 西 , 尤 其 是 从 子 句 中 引 用 事 实 和 变 量 。<br />
获 取 变 量<br />
匿 名 谓 词 是 出 现 在 子 句 中 的 , 而 这 个 子 句 可 能 含 有 变 量 。 对 那 些 在 匿 名 谓 词 出 现 之 前 绑 定 的 变 量 , 在<br />
匿 名 谓 词 中 可 以 使 用 。 下 面 的 代 码 说 明 了 如 何 获 取 变 量 的 :<br />
domains<br />
pred = (integer) -> integer.<br />
59
class predicates<br />
createAdder : (integer A) -> pred Adder.<br />
clauses<br />
createAdder(A) = { (X) = X+A }.<br />
clauses<br />
run() :-<br />
Add17 = createAdder(17),<br />
A = Add17(4),<br />
B = Add17(20),<br />
stdio::writef("A = %, B = %", A, B).<br />
用 17 做 参 数 调 用 createAdder, 这 时 createAdder 子 句 中 的 A 是 17, 因 而 结 果 是 { (X) = X+17 }。<br />
我 们 说 匿 名 谓 词 获 取 了 变 量 A。Add17 是 一 个 把 17 加 到 自 身 参 数 的 谓 词 , 输 出 的 结 果 就 是 :<br />
获 取 省 略 符<br />
A = 21, B = 37<br />
匿 名 谓 词 可 以 获 取 省 略 符 变 量 :<br />
clauses<br />
ppp(...) :-<br />
W = { () :- stdio::write(...) },<br />
qqq(W).<br />
W 获 取 了 省 略 符 变 量 。qqq 收 到 一 个 0 元 维 的 谓 词 , 当 这 个 谓 词 被 调 用 时 , 获 取 的 省 略 符 变 量 就 会 写<br />
到 标 准 输 出 设 备 上 去 。<br />
获 取 事 实<br />
匿 名 谓 词 可 以 获 取 事 实 。 如 果 匿 名 变 量 是 由 类 谓 词 创 建 的 , 它 就 可 以 访 问 类 事 实 ; 如 果 是 由 对 象 谓 词<br />
创 建 的 , 它 就 既 可 以 访 问 对 象 事 实 又 可 以 访 问 类 事 实 。 下 面 的 代 码 获 取 的 是 类 事 实 :<br />
class facts<br />
count : integer := 0.<br />
clauses<br />
seq() = { () = count :- count := count+1 }.<br />
clauses<br />
run() :-<br />
A = seq(),<br />
B = seq(),<br />
stdio::writef("A1 = %, ", A()),<br />
stdio::writef("B1 = %, ", B()),<br />
stdio::writef("A2 = %, ", A()),<br />
stdio::writef("B2 = %", B()).<br />
A 和 B 都 会 使 类 事 实 计 数 增 加 , 所 以 结 果 是 :<br />
A1 = 1, B1 = 2, A2 = 3, B2 = 4<br />
对 象 谓 词 中 可 以 获 取 对 象 事 实 。 假 设 seq 是 myClass 中 的 对 象 谓 词 , 下 面 的 代 码 说 明 了 获 取 对 象 事 实 :<br />
60
facts<br />
count : integer := 0.<br />
clauses<br />
seq() = { () = count :- count := count+1 }.<br />
clauses<br />
run() :-<br />
A = myClass::new():seq(),<br />
B = myClass::new():seq(),<br />
stdio::writef("A1 = %, ", A()),<br />
stdio::writef("B1 = %, ", B()),<br />
stdio::writef("A2 = %, ", A()),<br />
stdio::writef("B2 = %", B()).<br />
这 里 ,A 和 B 来 自 不 同 的 对 象 , 它 们 有 各 自 的 计 数 , 所 以 输 出 是 :<br />
A1 = 1, B1 = 1, A2 = 2, B2 = 2<br />
技 术 上 来 说 , 类 版 本 的 匿 名 谓 词 其 实 获 取 不 了 什 么 东 西 , 它 很 少 有 权 使 用 事 实 。 同 样 地 , 对 象 版 的 其<br />
实 也 没 有 获 取 事 实 , 它 获 取 的 是 This 并 通 过 This 访 问 了 对 象 事 实 。<br />
获 取 This<br />
嵌 套<br />
如 上 所 述 , 可 以 获 取 This 并 取 得 对 对 象 事 实 的 访 问 权 。 同 样 的 机 制 可 以 调 用 对 象 谓 词 :<br />
clauses<br />
seq() = { () = count :- inc() }.<br />
clauses<br />
inc() :- count := count+1.<br />
This 也 可 以 直 接 使 用 :<br />
clauses<br />
ppp() = { () = aaa::rrr(This) }.<br />
匿 名 谓 词 可 以 嵌 套 :<br />
clauses<br />
run() :-<br />
P = { (A) = { (B) = A+B } },<br />
Q = P(3300),<br />
R = P(2200),<br />
stdio::writef("Q(11) = %, ", Q(11)),<br />
stdio::writef("R(11) = %", R(11)).<br />
要 得 到 Q 用 3300 调 用 P, 这 样 A 是 3300 而 Q 就 是 { (B) = 3300+B} }, 同 样 R 是 { (B) =<br />
2200+B } }, 结 果 是 :<br />
Q(11) = 3311, R(11) = 2211<br />
Syntactic Sugar( 便 利 化 的 语 法 )<br />
61
如 果 不 需 要 参 数 , 可 以 把 它 们 略 过 。 下 面 这 个 代 码 片 断 :<br />
P = { (_) :- succeed },<br />
Q = { (_, _) = 0 },<br />
R = { (_, _, _) = _ :- fail }<br />
可 以 简 化 成 这 样 :<br />
P = { :- succeed },<br />
Q = { = 0 },<br />
R = { = _ :- fail }<br />
注 意 , 参 数 部 分 完 全 被 略 去 了 。 如 果 写 () 则 意 味 着 是 零 参 数 , 而 略 去 所 有 参 数 意 思 是 “ 有 适 当 的 ” 参<br />
数 。<br />
实 际 使 用 举 例<br />
这 节 内 容 显 示 了 匿 名 谓 词 的 便 利 性 。 例 子 中 假 定 PFC 中 的 core、std、stdio、list 和 string 等 范 围 是 开<br />
放 的 。<br />
哑 谓 词<br />
适 配<br />
用 匿 名 谓 词 来 创 建 哑 谓 词 值 是 很 方 便 的 :<br />
ppp( { = true } ), % 不 过 滤 (boolean)<br />
qqq( { :- succeed } ), % 不 过 滤 (determ)<br />
rrr( { = 17 } ), % 所 有 行 高 必 须 为 17<br />
有 的 时 候 要 用 一 个 谓 词 , 而 已 经 有 了 一 个 差 不 多 合 适 的 , 这 时 可 以 用 匿 名 谓 词 来 配 合 以 满 足 需 要 。<br />
适 配 索 引<br />
看 一 下 谓 词 write3:<br />
class predicates<br />
write3 : (function{integer, string} Indexer).<br />
clauses<br />
write3(Indexer) :-<br />
foreach I = std::fromTo(0,2) do<br />
write(Indexer(I), "\n")<br />
end foreach.<br />
Indexer 提 供 了 一 个 串 的 “ 数 组 ”,write3 可 以 写 出 以 索 引 号 为 0、1 和 2 的 三 个 串 。 因 此 ,write3<br />
设 定 “ 数 组 ” 索 引 号 是 从 0 开 始 的 。 不 过 , 我 们 想 用 一 个 索 引 号 从 1 开 始 的 “ 数 组 ”:<br />
class predicates<br />
myArray : (integer N) -> string Value.<br />
clauses<br />
62
参 数 适 配<br />
myArray(1) = "First" :- !.<br />
myArray(2) = "Second" :- !.<br />
myArray(3) = "Third" :- !.<br />
myArray(_) = _ :-<br />
raiseError().<br />
用 一 个 匿 名 谓 词 , 就 可 以 轻 而 易 举 地 使 索 引 号 从 1 开 始 的 数 组 满 足 索 引 号 从 0 开 始 的 使 用 要 求 :<br />
% myArray is 0-based, write3 requires 1-based<br />
Arr = { (N) = myArray(N+1) },<br />
write3(Arr)<br />
这 样 , 我 们 就 可 以 得 到 期 望 的 输 出 :<br />
First<br />
Second<br />
Third<br />
在 下 面 的 代 码 中 ,listChildren 将 为 每 一 个 “C 是 P 的 孩 子 ” 数 据 对 调 用 谓 词 ChildWriter:<br />
class predicates<br />
listChildren :(predicate{string,string} ChildWriter).<br />
clauses<br />
listChildren(CW) :-<br />
CW("Son1", "Father"),<br />
CW("Son2", "Father").<br />
不 过 , 现 在 我 们 想 用 谓 词 wParent 写 出 “P 是 C 的 父 母 ” 的 列 表 来 :<br />
class predicates<br />
wParent : (string Parent, string Child).<br />
clauses<br />
wParent(P, C) :-<br />
writef("% is the parent of %\n", P, C).<br />
wParent 所 用 的 参 数 刚 好 顺 序 是 相 反 的 , 可 以 很 容 易 地 用 一 个 匿 名 谓 词 来 调 整 它 :<br />
Swap = { (A,B) :- wParent(B,A) },<br />
listChildren(Swap)<br />
输 出 就 是 我 们 想 要 的 了 :<br />
Father is the parent of Son1<br />
Father is the parent of Son2<br />
我 们 还 可 以 丢 掉 不 需 要 的 参 数 , 比 如 调 用 谓 词 时 我 们 只 想 要 “Child”:<br />
class predicates<br />
wKnowParent : (string Child).<br />
clauses<br />
wKnowParent(C) :-<br />
writef("We know a parent of %\n", C).<br />
63
可 以 这 样 来 做 需 要 的 适 配 :<br />
Fewer = { (C,P) :- wKnowParent(C) },<br />
listChildren(Fewer)<br />
输 出 会 是 这 样 :<br />
We know a parent of Son1<br />
We know a parent of Son2<br />
我 们 还 可 以 使 用 哑 参 数 :<br />
More = { (_,P) :- addChildren(P, 1) }<br />
listChildren(More)<br />
这 里 的 addChildren 会 “ 把 孩 子 数 加 到 P 中 ”, 因 为 对 应 每 个 孩 子 的 调 用 addChild 都 提 供 了 一 个 “ 哑<br />
参 数 ”1。More 是 提 供 一 个 哑 参 数 并 丢 弃 一 个 参 数 的 适 配 器 。<br />
筛 选<br />
设 有 谓 词 :<br />
class predicates<br />
writeFiltered :(string L, filterPredicate{integer} Filter).<br />
clauses<br />
writeFiltered(Label, Filter) :-<br />
List = [1,2,3,4,5,6,7,8,9],<br />
FilteredList = filter(List, Filter),<br />
writef("%\t%\n", Label, FilteredList).<br />
过 滤 器 Filter 用 来 筛 选 表 [1,2,3,4,5,6,7,8,9], 筛 选 出 来 的 表 和 标 签 Label 写 到 标 准 输 出 设 备 上 。<br />
我 们 先 用 个 全 选 过 滤 器 :<br />
All = { :- succeed },<br />
writeFiltered("All", All)<br />
这 个 过 滤 器 对 任 何 元 素 都 成 功 , 所 以 输 出 是 全 表 :<br />
All [1,2,3,4,5,6,7,8,9]<br />
创 建 一 个 过 滤 器 对 任 何 元 素 都 失 败 也 很 简 单 :<br />
None = { :- fail },<br />
writeFiltered("None", None)<br />
输 出 就 是 个 空 表 :<br />
None []<br />
也 可 以 创 建 一 个 过 滤 器 选 出 大 于 3 的 元 素 和 能 被 3 整 除 的 元 素 :<br />
GreaterThan3 = { (X) :- X > 3 },<br />
64
输 出 是 :<br />
writeFiltered("> 3", GreaterThan3),<br />
Rem3 = { (X) :- 0 = X rem 3 },<br />
writeFiltered("Rem3", Rem3)<br />
> 3 [4,5,6,7,8,9]<br />
Rem3 [3,6,9]<br />
排 序<br />
表 包 里 有 排 序 谓 词 , 不 过 有 时 缺 省 的 顺 序 不 能 满 足 要 求 , 所 以 表 包 里 还 有 一 个 sortBy 谓 词 , 可 以 按 程<br />
序 员 定 义 的 比 较 操 作 对 元 素 排 序 。 我 们 用 这 个 谓 词 先 来 考 虑 一 下 串 的 排 序 :<br />
class predicates<br />
writeStringsSorted :<br />
(string Label, comparator{string} Comp).<br />
clauses<br />
writeStringsSorted(Label, C) :-<br />
List = ["John Wayne", "Uma Thurman",<br />
"Harrison Ford", "Nicolas Cage",<br />
"Elizabeth Taylor", "Cary Grant",<br />
"Jerry Lewis", "Robert De Niro"],<br />
Sorted = sortBy(C, List),<br />
write(Label, "\n"),<br />
foreach S = list::getMember_nd(Sorted) do<br />
writef(" %\n", S)<br />
end foreach.<br />
我 们 可 以 用 “normal” 比 较 符 调 用 谓 词 , 还 可 以 用 一 个 匿 名 谓 词 很 方 便 地 实 现 降 序 排 序 :<br />
Normal = compare,<br />
writeStringsSorted("Normal", Normal),<br />
Descending = { (A,B) = compare(B,A) },<br />
writeStringsSorted("Descending", Descending)<br />
输 出 是 这 样 的 :<br />
Normal<br />
Cary Grant<br />
Elizabeth Taylor<br />
Harrison Ford<br />
Jerry Lewis<br />
John Wayne<br />
Nicolas Cage<br />
Robert De Niro<br />
Uma Thurman<br />
Descending<br />
Uma Thurman<br />
Robert De Niro<br />
Nicolas Cage<br />
John Wayne<br />
Jerry Lewis<br />
Harrison Ford<br />
Elizabeth Taylor<br />
Cary Grant<br />
65
我 们 再 来 排 序 一 些 更 复 杂 的 元 素 。 下 面 的 一 些 人 名 使 用 这 样 的 域 :<br />
domains<br />
person = p(string First, string Last).<br />
作 为 演 示 , 我 们 用 这 个 谓 词 :<br />
class predicates<br />
writePersonsSorted :<br />
(string Label, comparator{person} Comparator).<br />
clauses<br />
writePersonsSorted(Label, C) :-<br />
List = [p("John","Wayne"),<br />
p("Uma","Thurman"),<br />
p("Harrison","Ford"),<br />
p("Nicolas","Cage"),<br />
p("Elizabeth","Taylor"),<br />
p("Cary","Grant"),<br />
p("Jerry","Lewis"),<br />
p("Robert","De Niro")],<br />
Sorted = sortBy(C, List),<br />
write(Label, "\n"),<br />
foreach p(F,L) = list::getMember_nd(Sorted) do<br />
writef(" % %\n", F, L)<br />
end foreach.<br />
同 样 , 我 们 也 可 以 用 正 常 和 降 序 比 较 符 :<br />
Normal = compare,<br />
writePersonsSorted("Normal", Normal),<br />
Descending = { (A,B) = compare(B,A) },<br />
writePersonsSorted("Descending", Descending)<br />
因 为 比 较 谓 词 对 函 子 使 用 从 左 到 右 的 词 典 顺 序 , 结 果 与 前 面 的 一 样 :<br />
Normal<br />
Cary Grant<br />
Elizabeth Taylor<br />
Harrison Ford<br />
Jerry Lewis<br />
John Wayne<br />
Nicolas Cage<br />
Robert De Niro<br />
Uma Thurman<br />
Descending<br />
Uma Thurman<br />
Robert De Niro<br />
Nicolas Cage<br />
John Wayne<br />
Jerry Lewis<br />
Harrison Ford<br />
Elizabeth Taylor<br />
Cary Grant<br />
但 用 更 复 杂 些 的 域 我 们 还 可 以 创 建 一 个 比 较 符 , 不 是 按 名 而 是 按 姓 来 排 序 :<br />
66
获 取 关 联<br />
LN = { (p(_,L1), p(_, L2)) = compare(L1,L2) },<br />
writePersonsSorted("LastName", LN)<br />
这 正 是 我 们 期 望 的 结 果 :<br />
LastName<br />
Nicolas Cage<br />
Robert De Niro<br />
Harrison Ford<br />
Cary Grant<br />
Jerry Lewis<br />
Elizabeth Taylor<br />
Uma Thurman<br />
John Wayne<br />
前 面 说 过 , 匿 名 谓 词 一 个 很 有 用 的 特 性 是 获 取 关 联 的 能 力 。 下 面 的 例 子 说 明 如 何 使 用 这 个 特 性 。<br />
Background threads( 后 台 线 程 )<br />
启 动 线 程 的 例 程 有 一 个 空 元 谓 词 , 会 在 一 个 新 线 程 中 运 行 它 。 不 过 我 们 常 常 需 要 传 递 一 些 输 入 数 据 给<br />
新 线 程 中 的 作 业 。 可 以 有 多 种 办 法 , 但 最 简 单 的 办 法 是 用 匿 名 谓 词 。<strong>Visual</strong> <strong>Prolog</strong> 例 集 ( 可 以 在 IDE 中 安<br />
装 ) 中 的 bgDemo 工 程 用 的 就 是 这 个 办 法 。 这 个 工 程 中 有 一 个 表 格 , 可 以 启 动 后 台 作 业 , 并 用 表 格 中 一<br />
个 jobControl 控 件 显 示 作 业 的 状 态 信 息 。 后 台 作 业 是 一 个 谓 词 , 它 接 收 jobLog, 这 个 控 件 可 以 用 来 报 告<br />
状 态 和 进 度 :<br />
domains<br />
job = (jobLog Log).<br />
jobLog 是 这 样 的 :<br />
interface jobLog<br />
properties<br />
completion : real (i).<br />
properties<br />
status : string (i).<br />
end interface jobLog<br />
作 业 通 过 设 置 完 成 属 性 (0 到 1) 来 报 告 完 成 进 度 。 同 样 , 状 态 属 性 可 以 用 来 反 映 作 业 的 当 前 状 态 。 状<br />
态 和 完 成 进 度 用 一 个 作 业 名 显 示 在 表 格 里 。 作 业 的 启 动 是 通 过 调 用 表 格 的 addJob 谓 词 :<br />
clauses<br />
addJob(JobName, Job) :-<br />
JobCtrl = jobControl::new(This),<br />
JobCtrl:name := JobName,<br />
JobCtrl:show(),<br />
assert(jobCtrl_fact(JobCtrl)),<br />
arrange(),<br />
JobLog = jobLog::new(JobCtrl),<br />
Action = { :- Job(JobLog) },<br />
_ = thread::start(Action).<br />
67
上 面 最 后 三 行 是 我 们 关 心 的 关 联 。thread::start 用 一 个 空 元 谓 词 作 参 数 , 但 作 业 是 一 个 以 jobLog<br />
为 参 数 的 谓 词 。 因 此 , 我 们 用 了 一 个 匿 名 谓 词 Action, 它 没 有 参 数 但 在 JobLog 上 调 用 Job。 匿 名 谓 词 从<br />
关 联 中 既 获 取 了 Job 又 获 取 了 JobLog, 因 而 它 们 的 值 可 以 传 递 给 新 线 程 , 尽 管 线 程 得 到 的 是 一 个 空 元 谓<br />
词 。bgDemo 工 程 中 的 作 业 差 不 多 是 个 空 作 业 , 只 是 操 控 jobLog。 作 业 是 这 个 样 子 的 :<br />
clauses<br />
job(Log, From, To) :-<br />
Log:status := "Step 1",<br />
foreach N1 = std::fromTo(From, To) do<br />
Log:completion :=<br />
(N1-From) / (To-From) / 2,<br />
programControl::sleep(3)<br />
end foreach,<br />
Log:status := "Step 2",<br />
foreach N2 = std::fromTo(From, To) do<br />
Log:completion :=<br />
(N2-From) / (To-From) / 2 + 0.5,<br />
programControl::sleep(3)<br />
end foreach,<br />
Log:status := "finished".<br />
从 From 到 To 这 里 有 两 个 循 环 , 计 算 完 成 进 度 并 把 它 设 置 给 Log。 它 还 要 在 循 环 前 , 循 环 中 和 循 环 后<br />
设 置 状 态 文 字 。 可 以 看 到 , 这 个 作 业 没 有 固 有 的 作 业 类 型 , 因 为 一 个 特 定 的 作 业 只 有 一 个 参 数 (jobLog),<br />
而 这 个 作 业 有 三 个 参 数 。 还 是 匿 名 谓 词 帮 了 忙 。<br />
在 表 格 中 添 加 作 业 的 代 码 是 这 样 的 :<br />
predicates<br />
onFileNew : window::menuItemListener.<br />
clauses<br />
onFileNew(_Source, _MenuTag) :-<br />
JF = jobForm::display(This),<br />
Job11 = {(L) :- job1::job(L, 1, 1000)},<br />
Job12 = {(L) :- job1::job(L, 200, 600)},<br />
Job13 = {(L) :- job1::job(L, 1200, 3000)},<br />
Job14 = {(L) :- job1::job(L, 1, 1000)},<br />
JF:addJob("job1.1", Job11),<br />
JF:addJob("job1.2", Job12),<br />
JF:addJob("job1.3", Job13),<br />
JF:addJob("job1.4", Job14),<br />
...<br />
在 实 际 的 程 序 中 ,From 和 To 不 会 是 常 数 , 它 会 是 从 别 的 地 方 传 递 来 的 参 数 。 在 这 种 情 况 下 , 匿 名 谓<br />
词 也 会 从 关 联 中 获 取 变 量 。 在 bgDemo 中 的 jobLog 说 明 了 匿 名 谓 词 又 一 种 使 用 方 法 , 它 传 递 完 成 进 度 和<br />
状 态 信 息 给 一 个 控 件 jobControl。jobControl 是 jobForm 中 的 一 个 GUI 控 件 , 它 以 适 当 的 形 式 表 现 得<br />
到 的 信 息 。 不 过 , 这 里 有 个 同 步 的 问 题 , 因 为 GUI 控 件 在 线 程 级 并 不 稳 定 , 而 在 这 里 我 们 是 从 一 个 后 台 线<br />
程 中 更 新 控 件 的 。 这 有 可 能 导 致 冲 突 , 因 为 是 主 线 程 在 画 该 控 件 。 解 决 的 办 法 是 把 控 件 的 更 新 交 给 GUI 线<br />
程 。 可 以 通 过 把 动 作 传 递 给 控 件 来 这 样 做 。 状 态 更 新 的 实 现 是 这 样 的 :<br />
clauses<br />
status(Status) :-<br />
Action = { :- jobCtrl:status := Status },<br />
jobCtrl:postAction(Action).<br />
68
Action 是 一 个 空 元 谓 词 , 它 会 设 置 jobCtrl 中 的 状 态 。 我 们 把 这 个 动 作 传 递 给 jobCtrl, 当 它 接 收 到<br />
action 时 就 会 调 用 Action 完 成 更 新 。 这 样 , 控 件 的 实 际 更 新 是 由 GUI 线 程 完 成 的 , 这 个 匿 名 谓 词 不 仅 获 取<br />
Status 变 量 而 且 获 取 了 jobCtrl 事 实 。<br />
匿 名 回 叫<br />
考 虑 一 下 给 远 端 服 务 发 送 命 令 的 情 况 。 命 令 的 执 行 是 异 步 的 , 所 以 执 行 一 个 命 令 也 还 需 要 一 个 回 叫 动<br />
作 , 执 行 完 了 命 令 就 调 用 这 个 动 作 。 也 就 是 说 , 为 执 行 命 令 需 要 调 用 这 样 的 谓 词 :<br />
predicates<br />
executeCommand :<br />
(command Cmd, predicate{} OnDone).<br />
基 于 这 个 谓 词 , 还 可 以 创 建 一 个 可 以 执 行 一 个 命 令 表 的 谓 词 , 前 一 个 命 令 执 行 完 了 接 着 执 行 下 一 个 命<br />
令 。 执 行 命 令 表 也 是 异 步 的 , 所 以 命 令 脚 本 都 执 行 完 了 也 需 要 调 用 一 个 动 作 。 脚 本 执 行 的 形 式 是 这 样 的 :<br />
predicates<br />
executeScript :<br />
(command* Script, predicate{} OnDone).<br />
如 果 脚 本 空 了 , 就 调 用 OnDone。 若 脚 本 有 一 个 命 令 H 及 剩 下 的 脚 本 T, 必 须 先 执 行 H, 完 成 之 后 执<br />
行 剩 下 的 脚 本 T。So the OnDone action we supply when executing H must execute T. 总 之 , 实 现<br />
会 是 这 样 的 :<br />
clauses<br />
executeScript([], OnDone) :-<br />
OnDone().<br />
executeScript([H|T], OnDone) :-<br />
DoneH = { :- executeScript(T, OnDone) },<br />
executeCommand(H, DoneH).<br />
我 们 用 了 一 个 匿 名 谓 词 来 完 成 剩 余 脚 本 的 执 行 , 这 个 谓 词 获 取 T 和 OnDone。<br />
事 实 变 量 的 赋 值<br />
赋 值 算 子 := 用 于 给 事 实 变 量 FactVariable 赋 予 新 值 。Term 必 须 能 求 值 得 到 适 当 的 类 型 ( 与 事 实 变<br />
量 相 同 的 类 型 或 是 其 子 类 型 )。<br />
事 实<br />
FactVariableAssignment:<br />
FactVariable := Term<br />
事 实 数 据 库 包 含 有 若 干 完 全 实 例 化 的 ( 根 基 ) 谓 词 头 部 的 相 应 事 实 , 这 些 事 实 是 在 事 实 段 声 明 的 。 事<br />
实 可 以 由 谓 词 调 用 来 访 问 , 只 要 把 事 实 名 当 谓 词 名 就 行 了 。 各 个 事 实 依 次 与 谓 词 调 用 进 行 匹 配 , 每 次 谓 词<br />
调 用 与 事 实 匹 配 了 则 成 功 , 可 能 还 会 带 有 对 下 一 个 事 实 的 回 溯 点 ; 当 事 实 数 据 库 中 再 也 没 有 其 它 的 事 实 时<br />
这 个 谓 词 调 用 就 失 败 了 。<br />
可 以 用 谓 词 assert/1、asserta/1 和 assertz/1 插 入 新 的 事 实 。assert/1 和 assertz/1 是 一 样 的 , 把 新 事<br />
实 插 入 到 事 实 列 表 的 尾 部 , 而 asserta/1 则 把 新 事 实 插 入 到 列 表 的 开 头 。<br />
69
已 有 的 事 实 可 以 用 谓 词 retract/1 和 retractAll 撤 消 。retract/1 撤 消 第 一 个 与 参 数 匹 配 的 事 实 , 并 且 可<br />
以 通 过 回 溯 撤 消 更 多 的 事 实 。retractAll 能 撤 消 所 有 与 参 数 匹 配 的 事 实 , 它 总 能 成 功 。<br />
运 算 符<br />
运 算 符 ( 算 子 ) 按 优 先 级 分 组 , 下 面 各 组 的 算 子 在 组 内 具 有 相 同 的 优 先 级 , 而 在 前 面 的 组 优 先 级 高 于<br />
后 面 组 的 优 先 级 。 如 , 一 元 加 减 号 ( 也 就 是 正 负 号 ) 优 先 级 高 于 幂 算 子 , 而 幂 算 子 的 优 先 级 又 高 于 乘 法 算<br />
子 , 等 等 。 圆 括 号 可 以 用 来 标 示 优 先 级 使 之 更 清 晰 。<br />
UnaryOperator: one of<br />
- +<br />
BinaryOperator: one of<br />
PowerOperator<br />
MultiplicationOperator<br />
AdditionOperator<br />
RelationOperator<br />
AndOperator<br />
OrOperator<br />
只 有 幂 算 子 是 右 结 合 的 , 其 它 所 有 算 子 都 是 左 结 合 的 。<br />
例 下 面 的 项 :<br />
7 + 3 * 5 * 13 + 4 + 3 = X / 6 ; A < 7, p(X)<br />
与 下 面 的 项 是 一 样 的 :<br />
((((7 + ((3 * 5) * 13)) + 4) + 3) = (X / 6)) ; ((A < 7) , p(X))<br />
也 就 是 说 , 最 外 层 是 两 个 “ 或 ” 关 系 的 项 , 其 中 第 一 个 项 是 一 个 “ 等 号 ” 关 系 项 而 第 二 个 是 一 个 “ 与 ”<br />
项 。<br />
算 术 运 算 符<br />
算 术 运 算 符 用 于 对 数 进 行 算 术 运 算 。 它 们 是 表 达 式 , 并 以 表 达 式 为 参 数 。 参 数 是 根 类 型 的 , 而 返 回 的<br />
结 果 具 有 通 用 类 型 ( 参 看 通 用 类 型 和 根 类 型 )。<br />
关 系 运 算 符<br />
PowerOperator:<br />
^<br />
MultiplicationOperator: one of<br />
* / div mod quot rem<br />
AdditionOperator: one of<br />
+ -<br />
关 系 运 算 符 是 公 式 , 以 表 达 式 为 参 数 。 由 于 这 个 特 性 , 所 以 它 们 是 非 结 合 的 。<br />
70
RelationOperator: one of<br />
= > < >= <<br />
先 对 左 边 的 项 做 计 算 , 而 后 是 右 边 的 , 最 后 将 结 果 做 比 较 。<br />
注 意 , 并 非 双 算 子 的 =, 是 比 较 两 个 值 , 而 = 是 要 合 一 两 个 项 ( 至 少 通 常 情 况 下 是 这 样 )。<br />
对 偶 的 表 达 式 A = B 与 (A = B) 也 是 有 差 别 的 。<br />
逻 辑 运 算 符<br />
与 算 子 (AndOperator) 和 或 算 子 (OrOperator) 是 公 式 , 以 公 式 为 参 数 , 它 们 都 是 左 结 合 的 。<br />
“,” 和 “and” 是 一 回 事 ,“;” 和 “or” 也 是 一 回 事 。<br />
AndOperator: one of<br />
, and<br />
OrOperator: one of<br />
; or<br />
And (,)<br />
一 个 “and” 项 “A, B” 的 处 理 过 程 如 下 : 先 对 左 子 项 A 求 值 , 如 果 求 值 失 败 , 整 个 “and” 项 就 失<br />
败 了 。 如 果 A 成 功 了 , 再 对 右 子 项 B 求 值 , 如 果 失 败 ,“and” 项 失 败 。 否 则 “and” 项 就 成 功 了 。 因 此 ,<br />
如 果 子 项 A 成 功 了 , 只 需 要 对 第 二 个 子 项 B 求 值 就 行 了 。<br />
例<br />
clauses<br />
ppp() :-<br />
qqq(), rrr().<br />
当 调 用 ppp 时 , 首 先 会 调 用 qqq, 如 果 qqq 成 功 了 , 则 会 调 用 rrr。 如 果 rrr 成 功 , 则 “and” 项 成 功 ,<br />
进 而 整 个 子 句 成 功 。<br />
Or (;)<br />
一 个 “or” 项 “A; B” 的 处 理 过 程 如 下 : 首 先 在 第 二 项 B 上 创 建 一 个 回 溯 点 , 然 后 对 第 一 项 A 求 值 。<br />
如 果 求 值 成 功 , 则 整 个 “or” 项 成 功 , 并 留 有 一 个 第 二 项 B 的 回 溯 点 。 如 果 第 一 项 求 值 失 败 了 , 第 二 项 上<br />
的 回 溯 点 就 被 激 活 。 激 活 后 ( 无 论 是 第 一 项 失 败 而 激 活 的 还 是 以 后 调 用 过 程 中 激 活 的 ), 就 对 第 二 项 B 求<br />
值 , 如 果 B 成 功 则 整 个 “or” 项 成 功 。 因 此 , 一 个 “or” 项 可 以 在 一 个 回 溯 点 上 成 功 , 而 回 溯 中 仅 需 要 对<br />
第 二 个 子 项 B 求 值 。<br />
注 意 , 目 前 “or” 项 只 能 用 在 子 句 体 的 最 外 层 , 或 是 用 在 目 标 中 。 以 后 的 版 本 会 对 此 作 出 修 改 。<br />
例<br />
clauses<br />
ppp() :-<br />
qqq(V), write(V), fail.<br />
qqq(X) :-<br />
X = 3 ; X = 7.<br />
调 用 ppp 时 首 先 调 用 qqq。qqq 会 先 在 X = 7 上 创 建 一 个 回 溯 点 , 再 计 算 X = 3。 这 时 ,X 会 绑 定 为 3,<br />
qqq 返 回 。 而 这 时 ppp 中 的 V 会 绑 定 为 3, 写 V( 即 3) 然 后 碰 到 fail,fail 总 是 失 败 , 这 样 就 又 会 回 到 qqq<br />
71
中 的 回 溯 点 。 回 溯 会 解 除 创 建 回 溯 点 以 来 所 有 的 绑 定 , 所 以 ppp 中 的 V 和 qqq 中 的 X 绑 定 都 解 除 了 。 然 后<br />
计 算 qqq 中 的 X = 7,X 被 绑 定 为 7, 回 到 ppp 中 ,V 被 绑 定 为 7 并 写 出 来 。 又 碰 到 fail, 此 时 在 ppp 中 已 经<br />
没 有 回 溯 点 了 , 所 以 ppp 失 败 。<br />
深 层 嵌 套 的 “or”<br />
可 以 在 子 句 中 嵌 套 “or”。<br />
clauses<br />
p(X) = Y :-<br />
(X = 1, !, Z = 3 or Z = 7), Y = 2*Z.<br />
这 里 使 用 了 关 键 字 “or”, 但 也 可 以 用 分 号 “;”, 推 荐 使 用 “or”。 它 主 要 是 用 在 条 件 测 试 中 :<br />
clauses<br />
isOutside(X) :-<br />
(X < 10 or X > 90),!.<br />
“or” 是 一 个 非 确 定 性 的 结 构 , 因 此 很 多 情 况 下 需 要 用 截 断 使 代 码 是 确 定 性 的 。 尤 其 是 在<br />
“if-then-else” 结 构 中 , 需 要 使 用 截 断 。<br />
clauses<br />
p(X) :-<br />
if (X = 1 or X > 17),! then<br />
...<br />
end if.<br />
今 后 的 版 本 中 非 确 定 性 条 件 是 允 许 的 , 因 而 截 断 会 隐 含 在 这 样 的 条 件 中 。 这 种 变 化 是 向 后 兼 容 的 , 已<br />
有 程 序 不 需 要 改 变 。<br />
Not<br />
not/1 用 一 个 项 作 参 数 。not(A) 的 计 算 , 首 先 计 算 A, 如 果 A 成 功 , 则 not(A) 失 败 , 如 果 A 失 败 , 则<br />
not(A) 成 功 。<br />
注 意 ,not(A) 不 会 绑 定 任 何 变 量 。 因 为 如 果 not(A) 成 功 则 A 会 失 败 , 而 失 败 的 项 不 会 绑 定 任 何 东 西 ;<br />
而 如 果 not(A) 失 败 , 也 不 会 绑 定 任 何 变 量 , 因 为 该 项 本 身 是 失 败 的 。 还 要 注 意 ,not(A) 不 会 在 带 有 回 溯<br />
点 的 情 况 下 成 功 , 因 为 如 果 not(A) 成 功 则 A 是 失 败 的 , 而 失 败 的 项 不 可 能 还 有 回 溯 点 。 这 也 就 意 味 着 , 所<br />
有 A 成 功 的 可 能 都 已 经 穷 尽 了 。<br />
fail/0 和 succeed/0<br />
fail/0 和 succeed/0 是 两 个 内 建 的 空 元 谓 词 , 前 者 总 是 失 败 而 后 者 总 是 成 功 , 此 外 它 们 没 有 别 的 效 果 。<br />
Cut( 截 断 )<br />
截 断 “!” 将 进 入 当 前 谓 词 以 来 创 建 的 所 有 回 溯 点 都 消 除 掉 , 这 包 括 对 后 继 子 句 的 所 有 回 溯 点 , 以 及 谓<br />
词 调 用 在 当 前 子 句 “!” 之 前 建 立 的 回 溯 点 。<br />
Cut:<br />
72
!<br />
例<br />
clauses<br />
ppp(X) :-<br />
X > 7,<br />
!,<br />
write("Greater than seven").<br />
ppp(_X) :-<br />
write("Not greater than seven").<br />
执 行 ppp 时 , 首 先 在 第 二 个 子 句 上 创 建 一 个 回 溯 点 , 然 后 执 行 第 一 个 子 句 。 如 果 “X > 7” 成 功 了 ,<br />
就 碰 到 了 截 断 “!”, 它 会 消 除 第 二 个 子 句 上 的 回 溯 点 。<br />
例<br />
clauses<br />
ppp() :-<br />
qqq(X),<br />
X > 7,<br />
!,<br />
write("Found one").<br />
ppp() :-<br />
write("Did not find one").<br />
clauses<br />
qqq(3).<br />
qqq(12).<br />
qqq(13).<br />
当 执 行 ppp 时 首 先 在 ppp 第 二 个 子 句 创 建 一 个 回 溯 点 , 接 着 调 用 qqq。 而 qqq 会 在 它 的 第 二 个 子 句 上<br />
创 建 一 个 回 溯 点 并 执 行 第 一 个 子 句 , 返 回 值 3。 这 样 , 在 ppp 中 的 X 就 绑 定 为 这 个 值 并 与 7 相 比 较 , 它 失 败<br />
了 , 控 制 就 会 回 退 到 qqq 的 第 二 个 子 句 上 。 在 执 行 qqq 的 第 二 个 子 句 之 前 , 会 在 它 的 第 三 个 子 句 上 创 建 一<br />
个 回 溯 点 , 执 行 第 二 个 子 句 返 回 的 值 是 12。 这 次 与 7 的 比 较 成 功 了 , 执 行 截 断 , 它 会 把 在 qqq 上 剩 下 的 回<br />
溯 点 以 及 在 ppp 第 二 个 子 句 上 的 回 溯 点 都 取 消 。<br />
Cut 范 围<br />
cut 范 围 是 指 截 断 的 作 用 域 , 其 意 义 是 : 一 个 cut, 只 能 撤 消 在 其 作 用 范 围 内 的 回 溯 点 , 而 在 这 个 范 围<br />
之 外 的 回 溯 点 则 不 受 影 响 , 仍 然 保 留 。<br />
谓 词 的 子 句 是 一 个 cut 范 围 , 也 就 是 说 , 一 个 cut( 至 多 ) 会 撤 消 进 入 这 个 谓 词 之 后 创 建 的 回 溯 点 , 在<br />
进 入 这 个 谓 词 之 前 创 建 的 那 些 回 溯 点 将 保 留 下 来 。<br />
例<br />
clauses<br />
aaa() :- p1_nd(), qqq().<br />
qqq() :- p2_nd(), !.<br />
aaa 调 用 p1_nd, 会 留 下 一 个 回 溯 点 , 然 后 又 调 用 qqq;qqq 又 调 用 p2_nd, 也 会 留 下 一 个 回 溯 点 ,<br />
接 着 就 碰 到 一 个 截 断 (cut)。 这 个 截 断 是 在 qqq 谓 词 的 截 断 范 围 内 的 , 所 以 它 只 能 废 掉 p2_nd 上 的 那 个<br />
回 溯 点 , 而 p1_nd 上 的 仍 然 保 留 。<br />
73
有 几 个 项 涉 及 到 截 断 范 围 ( 参 看 list comprehension、if-thenelse、foreach)。 这 里 以 if-then-else<br />
为 例 来 说 明 一 下 截 断 范 围 的 影 响 。 来 看 下 面 这 个 示 例 性 的 if-then-else 项 :<br />
if Cond then T1 else T2 end if<br />
条 件 Cond 是 一 个 截 断 范 围 , 在 Cond 中 的 cut 只 在 Cond 中 起 作 用 。 另 一 方 面 , 在 T1 和 T2 中 的 Cut,<br />
其 作 用 则 会 超 出 if-then-else 的 语 句 。 看 下 面 的 代 码 片 断 :<br />
X = getMember_nd([3,1,2]),<br />
if X = getMember_nd([3,3]), ! then<br />
write(X)<br />
else<br />
!<br />
end if,<br />
fail<br />
getMember_nd 是 一 个 非 确 定 谓 词 。 这 段 代 码 的 计 算 过 程 如 下 : 首 先 X 绑 定 为 3,getMember_nd<br />
留 下 一 个 回 溯 点 ( 这 样 以 后 X 还 可 以 为 1 再 为 2)。 接 着 , 要 计 算 if-then-else 项 的 条 件 , 这 个 条 件 的 第 一<br />
部 分 会 成 功 , 因 为 3 是 [3,3] 的 一 个 成 员 。 第 一 部 分 也 一 样 会 留 下 一 个 回 溯 点 , 这 样 它 就 能 多 次 检 查 X 是 否<br />
为 一 个 成 员 。 接 下 来 , 碰 到 一 个 截 断 , 这 个 截 断 是 在 if-then-else 语 句 条 件 部 分 中 的 , 故 只 在 这 个 范 围 中<br />
起 作 用 , 也 就 是 说 它 只 废 掉 了 第 二 个 getMember_nd 上 的 回 溯 点 , 而 第 一 个 getMember_nd 谓 词 上 的<br />
回 溯 点 仍 然 保 留 。 整 个 条 件 部 分 成 功 , 现 在 进 入 到 then- 部 分 , 写 出 “3”。if-then-else 之 后 我 们 遇 到<br />
了 fail, 这 样 就 又 回 溯 到 第 一 个 getMember_nd, 它 又 绑 定 X 为 1, 留 下 一 个 回 溯 点 ( 以 后 再 回 溯 时 可 以<br />
使 X 为 2)。 再 次 进 行 if-then-else 的 条 件 部 分 的 计 算 , 条 件 的 第 一 部 分 失 败 了 , 因 为 1 不 是 [3,3] 的 成 员 。<br />
这 样 就 进 入 到 else- 部 分 , 在 这 儿 遇 到 一 个 截 断 , 这 个 cut 是 在 选 择 项 的 else- 部 分 的 , 它 的 作 用 会 超 越<br />
if-then-else 项 , 因 此 第 一 个 getMember_nd 上 的 回 溯 点 被 撤 消 了 。 在 if-then-else 项 之 后 遇 到 了 fail,<br />
而 此 时 代 码 中 已 经 没 有 回 溯 点 , 这 段 代 码 就 失 败 了 , 而 X 总 也 不 会 为 2。<br />
List Comprehension( 述 求 表 )<br />
ListComprehensionTerm :<br />
[ Term || Term ]<br />
述 求 表 项 是 一 个 表 的 表 达 式 。 看 下 面 的 示 例 项 :<br />
[ Exp || Gen ]<br />
通 常 Gen 是 一 个 nondeterm 项 , 而 Exp 是 收 集 Gen 的 各 个 解 计 算 得 到 的 。 它 形 成 了 一 个 表 , 相 应 于<br />
Gen 的 第 一 个 解 的 是 Exp 的 表 中 的 第 一 个 元 素 , 等 等 。 这 个 表 , 是 述 求 表 项 的 结 果 。Exp 必 须 是 procedure<br />
( 或 erroneous)。Exp 和 Gen 都 是 cut 范 围 。<br />
述 求 表 一 般 读 为 : 如 Gen 所 述 , 那 样 的 Exp 的 表 。<br />
例<br />
[ X || X = getMember_nd(L), X div 2 = 0 ]<br />
它 可 以 读 为 :X 在 L 中 并 且 X 是 偶 数 的 X 的 表 。 所 以 , 这 个 表 达 式 是 L 中 的 偶 数 成 员 。<br />
例<br />
[ X + 1 || X = getMember_nd(L), X div 2 = 0 ]<br />
74
这 里 的 收 集 表 达 式 更 复 杂 了 , 要 说 这 个 项 也 更 麻 烦 了 : 这 样 的 (X+1) 的 表 …。 上 面 这 个 表 达 式 还 是<br />
找 L 中 的 偶 数 成 员 , 但 结 果 表 则 是 把 它 们 各 加 1。 因 而 , 它 与 下 面 这 个 表 达 式 是 完 全 等 价 的 :<br />
[ Y || X = getMember_nd(L), X div 2 = 0 , Y = X+1 ]<br />
这 个 项 就 比 较 易 于 说 :X 则 在 L 中 并 且 X 是 偶 数 ,Y 是 X+1, 那 样 的 Y 的 表 。<br />
访 问 对 象 成 员<br />
无 论 什 么 时 候 , 只 要 我 们 引 用 了 一 个 对 象 , 我 们 就 可 以 访 问 这 个 对 象 的 对 象 成 员 谓 词 。<br />
MemberAccess:<br />
Term : Identifier<br />
( 目 前 term( 项 ) 只 能 是 一 个 变 量 或 一 个 事 实 变 量 )。<br />
标 识 必 须 是 项 的 类 型 。<br />
在 实 现 内 部 , 调 用 对 象 成 员 谓 词 时 不 必 引 用 对 象 , 因 为 包 含 了 “This”, 参 看 范 围 。<br />
访 问 域 、 函 子 和 常 数<br />
对 域 、 函 子 和 常 数 , 可 以 将 它 们 视 为 类 成 员 来 访 问 , 即 便 是 在 接 口 中 声 明 的 也 一 样 。 这 也 意 味 着 , 如<br />
要 对 它 们 做 限 定 , 总 是 用 类 / 接 口 名 加 双 冒 号 。<br />
foreach<br />
ForeachTerm :<br />
foreach Term do Term end foreach<br />
看 下 面 的 foreach 示 例 项 :<br />
foreach Gen do Body end foreach<br />
通 常 Gen 是 一 个 nondeterm 项 。Body 对 每 一 个 Gen 的 解 求 值 。 当 Gen 失 败 则 foreach 项 成 功 , 不<br />
需 要 进 行 Body 计 算 。Body 必 须 是 procedure( 或 erroneous)。Gen 和 Body 都 是 cut 范 围 。<br />
这 个 示 例 的 项 , 类 似 于 下 面 的 fail 循 环 :<br />
Gen,<br />
Body,<br />
fail<br />
两 者 的 主 要 差 别 是 , 重 复 后 foreach 项 成 功 , 而 fail 循 环 是 失 败 。 因 此 ,foreach 项 可 以 后 跟 其 它 的<br />
项 , 还 可 以 嵌 套 。<br />
例<br />
foreach L = list::getMember_nd(LL) do<br />
write("
write(" >>\n")<br />
end foreach.<br />
这 里 的 LL 假 设 是 一 个 表 的 表 。 外 层 的 foreach 循 环 用 L 遍 访 这 个 表 , 所 以 L 是 一 个 表 。 内 层 的 foreach<br />
循 环 用 X 遍 访 L 中 的 元 素 。<br />
有 几 点 需 要 注 意 :<br />
• 在 关 键 字 do 和 end foreach 之 前 都 没 有 逗 号 ;<br />
• foreach 项 的 Body 是 一 个 cut 范 围 , 所 以 在 体 中 的 cut 不 会 影 响 重 复 ;<br />
• foreach 项 总 是 成 功 ( 或 引 起 异 常 ), 在 它 求 值 完 成 之 后 , 没 有 额 外 的 变 量 被 绑 定 。 因 此 ,foreach<br />
项 只 能 使 用 其 辅 助 功 能 。<br />
例<br />
clauses<br />
p(L) :-<br />
foreach X = list::getMember_nd(L) do<br />
stdio::write(X, "\n")<br />
end foreach,<br />
stdio::write("Finished\n").<br />
Foreach 可 以 用 来 替 代 传 统 的 fail 循 环 :<br />
clauses<br />
p(L) :-<br />
X = list::getMember_nd(L),<br />
stdio::write(X, "\n"),<br />
fail.<br />
p(_L) :-<br />
stdio::write("Finished\n").<br />
在 这 种 情 况 下 , 体 的 过 程 性 是 很 有 好 处 的 , 因 为 在 fail 循 环 中 就 怕 在 到 达 循 环 的 fail 之 前 的 偶 尔 失 败 。<br />
还 有 一 个 便 利 之 处 是 ,foreach 循 环 在 循 环 结 束 时 是 成 功 的 , 不 像 fail 循 环 是 失 败 , 所 以 可 以 在 同 一 个 子 句<br />
内 继 续 进 行 下 去 。<br />
foreach 还 可 以 嵌 套 :<br />
if-then-else<br />
clauses<br />
p(LL) :-<br />
foreach L = list::getMember_nd(LL) do<br />
foreach X = list::getMember_nd(L) do<br />
stdio::write(X, "\n")<br />
end foreach,<br />
stdio::write("Finished a list\n")<br />
end foreach,<br />
stdio::write("Finished all lists\n").<br />
按 不 同 条 件 执 行 一 组 语 句 。<br />
IfThenElseTerm:<br />
if Condition then Term Elseif-list-opt Else-opt end if<br />
76
Elseif:<br />
elseif Condition then Term<br />
Else:<br />
else Term<br />
下 面 两 个 项 是 等 价 的 :<br />
if Cond1 then T1 elseif Cond2 then T2 else T3 end if<br />
if Cond1 then T1 else<br />
if Cond2 then T2 else T3 end if<br />
end if<br />
来 看 一 下 示 例 的 if then else 项 :<br />
if Cond then T1 else T2 end if<br />
首 先 对 Cond 求 值 , 如 果 成 功 则 对 T1 求 值 , 否 则 对 T2 求 值 。Cond 不 允 许 有 回 溯 点 , 也 就 是 说 它 不 能<br />
是 多 态 的 (multi) 或 非 确 定 的 (nondeterm)。Cond 是 一 个 cut 范 围 ( 参 看 cut 范 围 )。<br />
例<br />
clauses<br />
w(X) :-<br />
if X div 2 = 0 and X > 3 then<br />
write("X is good")<br />
else<br />
write("X is bad"),<br />
nl<br />
end if,<br />
nl.<br />
这 个 例 子 中 , 要 注 意 几 点 :<br />
• 在 所 有 三 个 子 项 中 , 可 以 使 用 and 和 or 逻 辑 操 作 符 以 及 其 它 “ 组 合 ” 项 ;<br />
• 在 关 键 字 then、elseif、else 和 end if 之 前 没 有 逗 号 。<br />
为 有 良 好 的 可 读 性 , 推 荐 用 “or” 替 代 “;”。 同 样 , 当 表 示 一 个 逻 辑 条 件 时 ( 如 上 例 中 的 情 况 ),<br />
推 荐 用 “and” 替 代 “,”。<br />
省 去 else 部 分 是 “else succeed” 的 简 化 形 式 , 即 :<br />
if Cond then T1 end if<br />
是 下 面 的 简 写 形 式 :<br />
try-catch-finally<br />
if Cond then T1 else succeed end if<br />
try-catch-finally 语 句 提 供 了 一 种 处 理 给 定 程 序 代 码 块 中 可 能 出 现 异 常 的 方 法 。<br />
TryCatchTerm:<br />
try Term CatchFinally-list end try<br />
77
CatchFinally: one of<br />
catch Variable do Trap-Handler<br />
finally Finally-Handler<br />
Handler:<br />
Term<br />
try 结 构 有 一 个 项 及 一 个 捕 获 变 量 和 最 终 异 常 处 理 过 程 的 表 。 项 和 异 常 处 理 过 程 都 不 能 留 有 回 溯 点 ( 即<br />
不 能 是 multi 或 nondeterm)。<br />
带 有 多 个 异 常 处 理 过 程 的 try 结 构 等 效 于 单 个 异 常 处 理 过 程 的 try 结 构 的 嵌 套 , 下 面 的 项 :<br />
try<br />
Body<br />
catch Var1 do<br />
Handler1<br />
finally<br />
Handler2<br />
catch Var2 do<br />
Handler3<br />
end try<br />
与 下 面 的 嵌 套 项 是 等 价 的 :<br />
try<br />
try<br />
try<br />
Body<br />
catch Var1 do<br />
Handler1<br />
end try<br />
finally<br />
Handler2<br />
end try<br />
catch Var2 do<br />
Handler3<br />
end try<br />
try-catch<br />
看 下 面 这 个 try-catch 结 构 :<br />
try<br />
Body<br />
catch Var do<br />
Handler<br />
end try<br />
首 先 是 对 Body 求 值 。 如 果 Body 失 败 或 成 功 , 则 整 个 try 结 构 失 败 或 成 功 。 即 : 若 Body 并 未 因 一 个<br />
异 常 而 终 止 , 则 try 结 构 就 相 当 于 对 Body 求 值 。<br />
如 果 由 于 一 个 异 常 而 使 Body 终 止 了 , 这 个 异 常 就 被 捕 获 , 意 思 是 Var 首 先 被 绑 定 为 该 异 常 ( 在 PFC<br />
关 联 中 这 个 异 常 是 一 个 traceId), 接 着 对 Handler 求 值 。 这 种 情 况 下 该 结 构 就 是 带 有 绑 定 于 捕 获 异 常 的<br />
Var 对 Handler 的 求 值 。<br />
注 意 , 如 果 Body 因 异 常 而 终 止 了 , 它 本 身 并 不 会 绑 定 什 么 东 西 。<br />
78
例 处 理 一 个 文 件 不 能 读 的 情 况 :<br />
clauses<br />
read(Filename) = Contents :-<br />
try<br />
Contents = file::readFile(Filename)<br />
catch TraceId do<br />
stdio::writef("Could not read the file: %\n", Filename),<br />
exceptionDump::dumpToStdio(TraceId),<br />
Contents = ""<br />
end try.<br />
首 先 , 求 解 Contents = file::readFile(Filename), 如 果 它 并 未 因 为 read 异 常 而 终 止 , 就 会 返 回<br />
文 件 的 内 容 。<br />
如 果 出 现 了 异 常 , 就 会 带 着 绑 定 于 该 异 常 的 TraceId 对 异 常 处 理 过 程 求 解 。 此 时 , 会 将 一 个 消 息 写 到<br />
stdio 并 把 异 常 输 出 到 stdio, 最 后 把 Contents 设 为 空 串 作 为 结 果 返 回 。<br />
try-finally<br />
看 下 面 的 try-finally 结 构 :<br />
try<br />
Body<br />
finally<br />
Handler<br />
end try<br />
这 个 结 构 的 目 标 是 在 Body 之 后 对 Handler 求 值 , 而 不 管 Body 是 如 何 结 束 的 , 即 它 是 成 功 也 好 , 失<br />
败 也 好 , 因 异 常 而 终 止 也 好 ( 这 时 不 能 留 有 回 溯 点 ), 都 要 对 Handler 求 值 。<br />
求 值 过 程 是 这 样 的 :<br />
先 对 Body 求 值 , 若 成 功 再 执 行 Handler,try-finally 结 构 成 功 ; 若 失 败 也 执 行 Handler,try-finally<br />
结 构 失 败 ; 若 出 现 异 常 Exn, 还 是 执 行 Handler,try-finally 结 构 带 着 Exn 异 常 终 止 。<br />
例 确 保 在 使 用 过 后 odbcStatement 是 自 由 的 :<br />
clauses<br />
tryGetName(Connection, PersonId) = Name :-<br />
Stmt = odbcStatement::new(Connection),<br />
try<br />
Stmt:setParameterValue(1, core::integer(PersonId)),<br />
Stmt:execDirect("select name from person where id=?"),<br />
Stmt:fetch(),<br />
Name = Stmt:getParameterValue_string(1)<br />
finally<br />
Stmt:free()<br />
end try.<br />
即 使 fetch 失 败 或 是 其 它 什 么 原 因 出 现 异 常 了 ,Stmt 也 是 自 由 的 。<br />
转 换<br />
79
视 类 型 与 构 造 类 型<br />
接 口 定 义 对 象 的 类 型 , 支 持 某 个 接 口 的 所 有 对 象 都 具 有 这 个 接 口 定 义 的 类 型 。 以 后 , 我 们 把 对 象 类 型<br />
与 接 口 定 义 的 类 型 视 为 同 义 语 。<br />
接 口 定 义 了 类 型 , 这 些 类 型 就 可 以 在 谓 词 及 事 实 声 明 和 域 定 义 中 用 作 正 式 的 类 型 说 明 符 。<br />
对 象 具 有 了 任 意 它 所 支 持 接 口 的 对 象 类 型 , 它 也 就 可 以 当 作 任 意 这 些 类 型 的 对 象 来 使 用 , 也 就 是 说 ,<br />
对 象 类 型 被 转 换 为 任 意 支 持 的 对 象 类 型 。 下 面 要 说 明 , 这 种 转 换 多 数 情 况 下 是 自 动 进 行 的 。<br />
因 此 , 同 一 个 对 象 在 不 同 关 联 中 可 以 视 为 具 有 不 同 的 类 型 。 这 样 观 察 的 对 象 类 型 被 称 为 视 类 型 , 而 构<br />
造 对 象 的 类 的 类 型 被 称 作 构 造 类 型 或 定 义 类 型 。 构 造 类 型 也 是 一 个 视 类 型 。<br />
类 型 转 换<br />
如 上 所 述 , 对 象 可 以 当 成 任 意 它 所 支 持 的 接 口 的 类 型 来 使 用 。 这 一 节 要 描 述 各 种 支 持 类 型 的 转 换 是 怎<br />
么 进 行 的 。<br />
Conversion Upwards( 向 上 转 换 )<br />
如 果 某 个 项 静 态 地 归 类 于 某 个 类 型 T1, 而 T1 又 声 明 支 持 T2, 那 么 很 明 显 该 变 量 引 用 的 任 何 对 象 肯 定<br />
是 支 持 的 T2。 因 此 , 向 上 支 持 的 消 息 是 静 态 获 取 的 。 因 而 , 在 支 持 层 级 上 的 所 有 向 上 转 换 是 自 动 进 行 的 。<br />
例 假 设 有 接 口 bb, 它 支 持 接 口 aa 及 构 造 类 型 为 bb 的 类 bb_class。 来 看 下 面 的 代 码 :<br />
implement ...<br />
predicates<br />
ppp : (aa AA).<br />
clauses<br />
... :-<br />
BB = bb_class::new(), % (1)<br />
ppp(B). % (2)<br />
clauses<br />
ppp(AA) :- % (3)<br />
...<br />
BB = convert(bb,AA), % 可 以 转 换 , 因 为 AA 的 定 义 类 型 是 bb<br />
...<br />
在 (1) 那 行 我 们 创 建 了 一 个 bb_class 对 象 , 该 对 象 具 有 构 造 类 型 bb。 变 量 BB 是 对 这 个 新 对 象 的 引<br />
用 , 它 提 供 了 对 该 对 象 的 视 类 型 bb。 在 (2) 那 一 行 该 对 象 作 为 一 个 aa 对 象 传 递 给 了 ppp, 从 视 类 型 bb<br />
到 视 类 型 aa 的 转 换 是 隐 含 进 行 的 。 到 了 (3) 那 行 对 象 的 视 类 型 就 是 aa 了 , 尽 管 此 时 构 造 类 型 仍 是 bb。<br />
显 式 转 换<br />
显 式 转 换 是 通 过 调 用 转 换 谓 词 来 完 成 的 , 可 用 的 转 换 谓 词 有 若 干 个 。<br />
Checked Conversion<br />
谓 词 convert/2-> 和 tryConvert/2-> 用 于 安 全 地 完 成 从 一 个 类 型 到 另 一 个 类 型 的 转 换 。 这 两 个 谓 词 都<br />
给 不 出 真 实 的 声 明 , 伪 声 明 如 下 :<br />
predicates<br />
80
convert : ("type" Type, _ Value) -> Type ConvertedValue.<br />
tryConvert : ("type" Type, _ Value) -> Type ConvertedValue determ.<br />
convert/2-> 和 tryConvert/2-> 这 两 个 谓 词 都 用 “type” 作 第 一 个 参 数 , 以 任 意 类 型 的 一 个 值 做 第<br />
二 个 参 数 , 并 把 转 换 的 值 作 为 结 果 返 回 。<br />
如 果 不 能 进 行 转 换 ,convert/2-> 会 产 生 一 个 异 常 , 而 tryConvert/2-> 只 会 失 败 。<br />
注 意 , 如 果 源 类 型 是 目 标 类 型 的 子 类 型 , 使 用 convert/2-> 和 tryConvert/2-> 就 总 是 多 余 的 , 因 为 此<br />
时 会 隐 含 地 进 行 转 换 。<br />
报 告 。<br />
这 两 个 谓 词 可 以 用 在 以 下 场 合 :<br />
• 从 一 个 数 域 到 另 一 个 数 域 的 转 换 ;<br />
• 将 一 个 对 象 转 换 到 另 一 个 类 型 。<br />
编 译 器 如 果 能 确 定 一 个 转 换 肯 定 不 会 成 功 ( 比 如 要 转 换 的 数 域 间 根 本 没 有 交 集 ), 会 有 ( 但 并 非 总 有 )<br />
Conversion Downward( 向 下 转 换 )<br />
当 一 个 对 象 转 换 成 超 类 型 ( 如 支 持 的 接 口 ) 时 , 这 个 对 象 的 信 息 就 “ 不 记 得 ” 了 。 当 然 能 力 并 不 是 真<br />
的 丢 失 了 , 而 只 是 从 这 种 弱 化 能 力 接 口 的 关 联 中 来 看 对 象 时 看 不 到 了 。 在 很 多 情 况 下 需 要 恢 复 对 象 的 实 际<br />
能 力 , 因 此 需 要 对 它 们 进 行 向 下 及 向 上 的 转 换 。<br />
向 下 转 换 ( 一 般 ) 无 法 静 态 地 验 证 , 因 此 , 当 恢 复 “ 丢 失 ” 的 接 口 时 需 要 显 式 地 转 换 。<br />
例 尽 管 要 弄 个 在 支 持 层 级 中 向 上 转 换 类 型 的 有 意 义 的 说 明 例 子 很 简 单 , 但 说 明 有 意 义 的 向 下 转 换 的<br />
用 法 还 是 需 要 一 个 “ 真 实 ” 的 例 子 , 这 里 我 们 给 出 一 个 较 “ 真 实 ” 的 例 子 。<br />
假 设 我 们 要 实 现 一 组 相 似 类 型 的 对 象 , 比 如 一 组 支 持 某 个 视 类 型 的 对 象 , 我 们 需 要 这 样 的 集 合 用 于 若<br />
干 对 象 类 型 。 因 此 , 我 们 打 算 这 么 办 : 即 要 使 不 同 类 型 的 对 象 能 接 受 , 又 要 保 持 这 些 对 象 的 同 质 性 。<br />
方 法 是 标 准 化 的 : 我 们 使 集 合 的 实 际 实 现 基 于 对 象 的 类 型 , 这 个 类 型 是 所 有 对 象 都 支 持 的 。 然 后 用 一<br />
个 在 实 际 类 型 和 对 象 间 转 换 的 薄 层 来 构 造 集 合 的 特 殊 版 本 。 没 有 对 象 集 合 的 实 际 实 现 , 我 们 只 需 要 假 设 它<br />
形 式 上 存 在 于 下 面 的 类 和 接 口 中 :<br />
interface objectSet<br />
predicates<br />
insert : (object Elem).<br />
getSomeElem : () -> object determ.<br />
...<br />
end interface<br />
class objectSet_class : objectSet<br />
end class<br />
假 设 有 某 个 对 象 类 型 myObject 而 我 们 想 要 创 建 相 应 的 “set” 类 myObjectSet_class。 这 样 声 明<br />
myObjectSet_class:<br />
interface myObjectSet<br />
predicates<br />
insert : (myObject Elem).<br />
getSomeElem : () -> myObject determ.<br />
...<br />
end interface<br />
class myObjectSet_class : myObjectSet<br />
end class<br />
即 ,myObjectSet 有 objectSet 的 所 有 谓 词 , 但 每 当 object 出 现 时 就 替 换 成 myObject。<br />
81
myObjectSet_class 的 实 现 继 承 自 objectSet_class, 这 个 内 置 / 继 承 的 objectSet 将 取 得 该 集 合 的 成<br />
员 。 该 实 现 会 执 行 如 下 的 不 变 性 : 内 置 的 objectSet 将 只 包 含 myObject 类 型 的 对 象 ( 尽 管 从 “ 技 术 ” 上<br />
说 它 们 具 有 object 类 型 )。<br />
实 现 如 下 :<br />
implement myObjectSet_class<br />
inherit objectSet_class<br />
clauses<br />
insert(Elem) :-<br />
objectSet_class::insert(Elem). % (1)<br />
getSomeElem() = Some :-<br />
SomeObject = objectSet_class::getSomeElem(), % (2)<br />
Some = convert(myObject, SomeObject). % (3)<br />
...<br />
end implement<br />
在 (1) 行 ,Elem 自 动 从 类 型 myObject 转 换 为 object。 在 (2) 那 行 , 从 内 置 的 object 集 中 取 回<br />
一 个 对 象 。 理 论 上 说 这 个 对 象 具 有 object 类 型 , 但 从 不 变 性 上 看 这 个 对 象 也 支 持 myObject。 因 而 我 们<br />
可 以 安 全 地 恢 复 myObject 接 口 , 在 (3) 中 显 式 地 这 样 做 了 。<br />
Private 类 型 和 Public 类 型<br />
由 构 造 器 创 建 的 对 象 , 返 回 时 是 构 造 类 型 。 这 样 的 对 象 可 以 自 动 转 换 成 任 意 所 支 持 的 接 口 类 型 并 又 被<br />
显 式 地 返 回 。<br />
即 使 实 现 对 象 的 类 已 经 声 明 所 支 持 的 接 口 是 私 有 的 , 也 可 以 把 “ 公 用 ” 对 象 转 换 成 这 些 私 有 的 类 型 。<br />
无 论 怎 样 , 在 实 现 内 部 , 对 象 是 可 以 用 任 意 私 有 支 持 的 类 型 访 问 的 。 而 且 ,“This” 可 以 用 任 意 这 些<br />
私 有 支 持 的 类 型 递 交 到 实 现 之 外 。<br />
对 象 这 样 的 “ 私 有 ” 版 本 还 可 以 在 其 层 级 上 隐 含 地 向 上 转 换 并 显 式 地 向 下 转 换 回 来 。 事 实 上 , 这 样 的<br />
“ 私 有 ” 对 象 可 以 显 式 地 转 换 成 任 意 公 用 或 私 有 支 持 的 接 口 。<br />
所 以 , 一 个 对 象 会 有 两 面 , 公 用 的 一 面 和 私 有 的 一 面 , 而 私 有 的 一 面 包 括 了 公 用 类 型 。 对 象 不 能 从 一<br />
面 转 换 到 另 一 面 , 但 因 为 私 有 的 一 面 包 括 了 公 用 类 型 , 所 以 私 有 的 一 面 可 以 转 换 成 任 意 支 持 的 类 型 。<br />
Unchecked Conversion<br />
谓 词 uncheckedConvert/2 用 于 进 行 基 于 内 存 表 示 法 的 非 安 全 性 转 换 。 这 个 谓 词 并 不 对 内 存 做 任 何 修<br />
改 , 它 只 是 强 迫 编 译 器 对 所 指 的 存 储 片 断 解 释 为 另 外 的 类 型 。<br />
注 意 , 这 个 谓 词 是 很 不 安 全 的 , 使 用 时 要 小 心 。<br />
这 个 谓 词 主 要 用 于 与 其 它 语 言 的 接 口 , 来 解 释 其 它 语 言 对 内 存 映 象 的 使 用 方 法 。 它 只 能 使 用 在 大 小 完<br />
全 一 样 的 内 存 片 上 , 而 有 很 多 种 数 据 是 用 指 针 代 表 的 , 这 样 的 数 据 有 相 同 的 大 小 。<br />
例<br />
predicates<br />
uncheckedConvert : ("type" Type, _ Value) -> Type ConvertedValue.<br />
predicates<br />
interpretBufferAsString : (pointer BufferPointer) -> string Value.<br />
clauses<br />
interpretBufferAsString(BufferPointer) = uncheckedConvert(string,BufferPointer).<br />
82
这 个 谓 词 将 把 一 个 指 针 表 示 的 缓 冲 区 解 释 ( 转 换 ) 为 一 个 串 。 只 有 这 个 内 存 块 真 的 可 以 正 确 地 表 示 成<br />
一 个 串 , 它 才 是 有 意 义 的 。<br />
异 常 处 理<br />
本 节 描 述 <strong>Visual</strong> <strong>Prolog</strong> 中 异 常 处 理 的 低 级 结 构 。PFC 在 这 个 低 级 机 制 之 上 还 有 一 个 较 高 级 的 层 次 ( 参<br />
看 异 常 处 理 指 南 )。<br />
异 常 处 理 的 基 础 是 基 于 内 建 谓 词 errorExit/1 及 try-catch 语 言 结 构 的 。<br />
• errorExit/1 产 生 一 个 异 常<br />
• try-catch 为 某 个 计 算 设 置 异 常 处 理 程 序 。<br />
当 errorExit/1 调 用 时 , 当 前 激 活 的 异 常 处 理 程 序 被 调 用 , 这 个 异 常 处 理 程 序 是 按 原 来 的 关 联 执 行 的 ,<br />
这 个 关 联 是 原 来 设 置 的 而 不 是 发 生 异 常 那 里 的 关 联 。 调 用 时 的 参 数 传 递 给 了 异 常 处 理 程 序 , 这 个 参 数 必 须<br />
以 某 种 方 式 提 供 需 要 的 异 常 描 述 。<br />
与 其 它 运 行 时 例 程 一 道 , 在 这 个 系 统 之 上 就 可 以 建 立 起 高 级 的 异 常 处 理 机 制 了 。 不 过 运 行 时 系 统 访 问<br />
程 序 及 其 如 何 处 理 异 常 等 问 题 已 经 超 出 本 文 档 的 范 围 , 就 不 介 绍 了 。<br />
try-catch 的 第 一 个 参 数 是 与 新 异 常 处 理 程 序 一 道 执 行 的 项 ; 第 二 个 参 数 必 须 是 一 个 变 量 。 如 果 异 常 处<br />
理 程 序 被 激 活 , 这 个 变 量 将 绑 定 于 errorExit/1 被 调 用 时 的 值 。 第 三 个 参 数 是 异 常 处 理 程 序 , 如 果<br />
errorExit/1 被 调 用 则 会 激 活 这 个 异 常 处 理 程 序 。<br />
异 常 处 理 程 序 可 以 访 问 第 二 个 参 数 说 明 的 变 量 , 因 而 可 以 检 查 发 生 了 什 么 异 常 。<br />
例<br />
clauses<br />
p(X) :-<br />
try<br />
dangerous(X)<br />
catch Exception do<br />
handleDangerous(Exception)<br />
end try.<br />
如 果 在 执 行 dangerous 时 出 现 了 异 常 ,Exception 就 会 绑 定 为 异 常 值 ,try-catch 控 制 将 转 到 的 第 三<br />
个 参 数 , 在 这 里 就 是 把 Exception 传 递 给 handleDangerous。<br />
内 建 实 体<br />
<strong>Visual</strong> <strong>Prolog</strong> 有 一 个 内 含 的 类 , 提 供 了 所 有 内 建 的 常 数 、 域 及 谓 词 的 声 明 和 实 现 。 这 些 内 建 的 常 数 、<br />
域 及 谓 词 既 可 以 用 在 编 译 时 ( 如 在 #if ... 结 构 中 ) 也 可 以 用 在 实 现 中 ( 由 运 行 时 支 持 )。 每 个 编 译 单 元 隐<br />
含 地 包 括 了 这 个 内 含 类 的 声 明 。 可 以 在 内 建 项 的 名 称 前 使 用 “::” 以 与 其 它 同 名 的 实 体 相 区 分 。<br />
注 意 , 子 句 变 量 This 是 在 对 象 谓 词 子 句 中 自 动 定 义 的 。<br />
运 算 符<br />
运 算 符 描 述 备 注<br />
83
-( 一 元 ) 一 元 减 ( 负 号 )<br />
^ 幂 对 64 位 整 数 没 有 定 义<br />
*, / 乘 、 除 法<br />
div, mod 整 数 除 法 取 商 和 取 余 对 实 数 无 定 义<br />
quot, rem 整 数 除 法 取 商 和 取 余 对 实 数 无 定 义<br />
+, - 加 、 减 法<br />
• 上 面 的 运 算 符 是 按 优 先 级 由 高 到 低 排 列 的 ;<br />
• 所 有 的 乘 法 和 除 法 运 算 符 优 先 级 是 一 样 的 ;<br />
• 幂 运 算 符 是 右 结 合 的 ;<br />
• 所 有 其 它 运 算 符 都 是 左 结 合 的 。<br />
所 有 二 元 运 算 符 都 有 两 个 参 数 , 这 两 个 参 数 基 类 型 相 同 , 返 回 的 值 也 是 同 样 的 基 类 型 。 操 作 数 和 结 果<br />
的 类 型 可 以 应 用 普 通 子 类 型 规 则 进 行 转 换 。<br />
整 数 除 法<br />
当 计 算 结 果 是 正 数 时 ,div 与 quot 没 有 什 么 区 别 ; 但 当 结 果 是 负 值 时 ,div 的 取 整 使 用 最 接 近 的 最 小<br />
整 数 而 quot 是 使 用 最 接 近 的 最 大 整 数 。mod 是 对 应 于 div 的 余 数 , 而 rem 是 对 应 于 quot 的 余 数 。<br />
A B A div B A mod B A quot B A rem B<br />
15 7 2 1 2 1<br />
-15 7 -3 6 -2 -1<br />
15 -7 -3 -6 -2 1<br />
-15 -7 2 -1 2 -1<br />
常 数<br />
compilation date<br />
compilation time<br />
compiler buildDate<br />
compiler version<br />
maxFloatDigits<br />
null<br />
nullHandle<br />
invalidHandle<br />
platform bits<br />
platform name<br />
编 译 日 期<br />
编 译 时 间<br />
编 译 器 的 构 建 日 期<br />
编 译 器 版 本<br />
定 义 编 译 器 支 持 的 数 字 位 数 的 最 大 值<br />
缺 省 的 空 指 针<br />
值 为 零 的 句 柄 类 型 的 一 个 特 殊 常 数<br />
表 示 非 法 的 ( 值 为 -1) 句 柄 类 型 的 一 个 特 殊 常 数<br />
定 义 编 译 平 台 的 数 字 能 力<br />
定 义 目 标 平 台 名 称<br />
编 译 日 期<br />
compilation_date : string = "YYYY-MM-DD".<br />
84
这 里 的 YYYY 是 代 表 年 的 数 字 ,MM 是 代 表 月 份 的 数 字 ,DD 是 代 表 日 的 数 字 。<br />
编 译 时 间<br />
compilation_time : string = "HH-MM-SS".<br />
这 里 的 HH 代 表 小 时 ,MM 代 表 分 钟 ,SS 代 表 秒 。<br />
编 译 器 构 建 日 期<br />
compiler_buildDate : string = "YYYY-MM-DD HH-MM-SS".<br />
编 译 器 的 构 建 日 期 。<br />
编 译 器 版 本<br />
编 译 器 的 版 本 , 这 个 数 值 与 编 译 器 的 版 本 相 关 。<br />
maxFloatDigits<br />
compiler_version = 6003.<br />
定 义 编 译 器 支 持 的 数 字 位 数 的 最 大 值 。<br />
maxFloatDigits = 19.<br />
null<br />
null : pointer = uncheckedConvert(pointer, 0).<br />
值 为 零 的 指 针 类 型 的 一 个 特 殊 常 数 。<br />
nullHandle<br />
值 为 零 的 句 柄 类 型 的 一 个 特 殊 常 数 。<br />
invalidHandle<br />
nullHandle : handle = uncheckedConvert(handle, 0).<br />
其 值 (-1) 表 示 非 法 的 句 柄 类 型 的 一 个 特 殊 常 数 。<br />
platform_bits<br />
invalidHandle : handle = uncheckedConvert(handle, 0xFFFFFFFF).<br />
编 译 平 台 的 数 字 能 力 。<br />
platform_bits = 32.<br />
85
platform_name<br />
域<br />
目 标 编 译 平 台 名 称 。<br />
platform_name : string = "Windows 32bits".<br />
char<br />
string<br />
string8<br />
symbol<br />
binary<br />
binaryNonAtomic<br />
integer<br />
integer64<br />
unsigned<br />
unsigned64<br />
real<br />
real32<br />
pointer<br />
handle<br />
boolean<br />
factDB<br />
compareResult<br />
宽 ( 两 字 节 ) 字 符<br />
以 两 个 零 字 节 结 尾 的 宽 字 符 序 列<br />
以 一 个 零 字 节 结 尾 的 ASCII ( 单 字 节 ) 字 符 序 列<br />
以 两 个 零 字 节 结 尾 的 宽 字 符 序 列<br />
字 节 序 列<br />
字 节 序 列<br />
有 符 号 整 数<br />
有 符 号 整 数<br />
无 符 号 整 数<br />
无 符 号 整 数<br />
浮 点 数<br />
浮 点 数<br />
指 向 内 存 地 点 的 4 字 节 指 针<br />
指 向 内 存 地 点 的 4 字 节 指 针<br />
布 尔 值<br />
命 名 了 的 内 部 数 据 库 描 述 符<br />
比 较 结 果 的 值<br />
char<br />
宽 字 符 。<br />
char<br />
这 个 域 的 值 是 UNICODE 字 符 , 由 两 个 字 节 无 符 号 数 实 现 。<br />
对 这 个 域 的 值 的 操 作 , 只 能 有 赋 值 和 ( 字 典 意 义 上 的 ) 比 较 。 字 符 映 象 语 法 如 下 :<br />
Char_image :<br />
' Char_value '<br />
Char_value :<br />
Letter<br />
Digit<br />
Graphical_symbol<br />
\ Escape_seq<br />
Escape_seq:<br />
t<br />
n<br />
r<br />
86
\<br />
'<br />
"<br />
u HHHH<br />
上 面 的 HHHH 对 应 于 4 个 十 六 进 制 数 。 还 有 , 反 斜 杠 和 单 引 号 只 能 由 换 码 序 列 来 表 示 。<br />
compareResult<br />
这 是 一 个 内 建 的 域 , 用 来 定 义 一 个 比 较 结 果 。 内 建 谓 词 compare 的 结 果 就 是 这 个 域 的 。<br />
domains<br />
compareResult = less; equal; greater.<br />
string<br />
以 宽 零 结 尾 的 宽 字 符 序 列 。<br />
string<br />
串 是 UNICODE 字 符 序 列 。 它 是 由 一 个 指 向 以 宽 零 结 尾 的 宽 字 符 序 列 的 指 针 实 现 的 。 这 个 域 的 值 只 能<br />
进 行 赋 值 与 ( 字 典 意 义 上 的 ) 比 较 操 作 。 在 源 代 码 中 , 可 以 用 以 双 引 号 括 起 的 字 符 序 列 表 示 一 个 字 符 串 。<br />
StringLiteral:<br />
StringLiteralPart-list<br />
StringLiteralPart :<br />
@" AnyCharacter-list-opt "<br />
" CharacterValue-list-opt "<br />
字 符 串 由 一 个 或 多 个 连 接 起 来 的 StringLiteralPart 组 成 。 带 有 @ 的 StringLiteralPart 不 使 用 换 码<br />
序 列 , 而 不 带 @ 的 StringLiteralPart 则 使 用 以 下 的 换 码 序 列 :<br />
• \\ 表 示 \<br />
• \t 表 示 制 表 符<br />
• \n 表 示 换 行 符<br />
• \r 表 示 回 车<br />
• \' 表 示 单 引 号<br />
• \" 表 示 双 引 号<br />
• \u 后 跟 四 个 十 六 进 制 数 表 示 相 应 的 Unicode 字 符 。<br />
串 中 的 双 引 号 只 能 由 换 码 序 列 来 表 示 , 而 单 引 号 可 以 用 换 码 序 列 或 图 形 符 号 两 种 方 法 来 表 示 。<br />
string8<br />
内 建 的 string8 域 这 个 项 是 一 个 ASCII 字 符 序 列 。 它 是 由 一 个 指 向 零 结 尾 的 ASCII 字 符 序 列 的 指 针 实 现<br />
的 。 这 个 域 的 值 只 能 进 行 赋 值 与 ( 字 典 意 义 上 的 ) 相 等 比 较 操 作 。 目 前 , 对 这 个 域 来 说 , 不 能 使 用 文 字 。<br />
(Currently no literals are allowed for this domain.)<br />
symbol<br />
87
以 宽 零 结 尾 的 宽 字 符 序 列 。<br />
symbol<br />
与 串 一 样 ,symbol 也 是 一 个 UNICODE 字 符 序 列 。 它 是 由 一 个 指 向 包 含 串 的 symbol 表 的 入 口 指 针 实<br />
现 的 。 对 它 可 以 做 的 操 作 与 串 一 样 。<br />
symbol 的 映 象 是 由 串 文 字 ( 用 双 引 号 包 围 的 串 ) 来 表 示 的 。 它 与 串 在 很 大 程 度 上 是 可 以 互 换 的 , 但<br />
它 们 的 存 储 方 式 不 相 同 。symbol 被 放 在 一 个 关 注 表 中 , 它 们 的 地 址 ( 而 不 是 symbol 本 身 ) 存 储 起 来 用 于<br />
代 表 对 象 。 这 意 味 着 symbol 可 以 快 速 地 匹 配 , 而 且 如 果 它 重 复 地 出 现 在 程 序 中 时 占 用 存 储 空 间 很 小 。 串<br />
则 不 是 放 在 关 注 表 中 的 , 进 行 匹 配 时 <strong>Visual</strong> <strong>Prolog</strong> 要 逐 个 字 符 地 进 行 检 查 。<br />
binary<br />
N 个 字 节 的 序 列 。<br />
binary<br />
这 个 域 的 值 用 于 保 存 二 进 制 数 。 它 是 由 指 向 这 个 字 节 序 列 的 一 个 指 针 实 现 的 。 这 个 项 的 长 度 放 在 字 节<br />
序 列 的 前 面 , 占 四 个 字 节 。 这 四 个 字 节 的 值 为 :<br />
TotalNumberOfBytesOccupiedByBinary = ByteLen + 4<br />
ByteLen 是 二 进 制 项 本 身 的 长 度 。<br />
对 这 个 域 的 值 只 能 进 行 赋 值 和 比 较 操 作 。 比 较 操 作 的 方 法 如 下 :<br />
• 如 果 两 个 项 长 度 不 一 , 长 度 大 的 那 个 项 大 ;<br />
• 如 果 两 个 项 长 度 一 样 , 就 按 无 符 号 数 逐 字 节 地 比 较 , 比 较 到 不 一 样 的 字 节 时 就 停 止 , 那 个 字 节 的<br />
比 较 结 果 就 是 这 两 个 项 的 比 较 结 果 。 如 果 字 节 都 一 样 , 那 就 是 相 等 。<br />
二 进 制 映 象 的 内 容 语 法 由 Binary 规 则 确 定 :<br />
Binary :<br />
$ [ Byte_value-comma-sep-list-opt ]<br />
Byte_value :<br />
Expression<br />
各 个 表 达 式 的 值 应 是 在 编 译 时 可 计 算 得 到 的 , 且 值 的 范 围 在 0 到 255 之 间 。<br />
binaryNonAtomic<br />
N 个 字 节 的 序 列 。<br />
binaryNonAtomic<br />
同 binary, 但 包 含 指 针 。<br />
integer<br />
有 符 号 整 数 。<br />
integer<br />
88
这 个 域 的 值 占 四 个 字 节 。 可 以 进 行 算 术 运 算 (+, -, /, *, ^)、 比 较 、 赋 值 、div、mod、quot 及 rem<br />
操 作 。 值 的 范 围 是 -2147483648 到 2147483647。<br />
它 的 文 字 表 示 方 法 由 Integer 规 则 确 定 :<br />
Integer :<br />
Add_operation-opt 0o Oct_number<br />
Add_operation-opt Dec_number<br />
Add_operation-opt 0x Hex_number<br />
Add_operation :<br />
+<br />
-<br />
Oct_number :<br />
Oct_digit-list<br />
Oct_digit : one of<br />
0 1 2 3 4 5 6 7<br />
Dec_number :<br />
Dec_digit-list<br />
Dec_digit : one of<br />
Oct_digit 8 9<br />
Hex_number :<br />
Hex_digit-list<br />
Hex_digit : one of<br />
Dec_digit a b c d e f A B C D E F<br />
integer64<br />
有 符 号 整 数 。<br />
integer64<br />
这 个 域 的 值 占 八 个 字 节 。 值 的 范 围 是 -2^63 = -9,223,372,036,854,775,808 到 2^63-1 =<br />
9,223,372,036,854,775,807。 其 文 字 表 示 方 法 及 可 以 进 行 的 操 作 与 integer 相 同 。<br />
unsigned<br />
无 符 号 整 数 。<br />
unsigned<br />
这 个 域 的 值 占 四 个 字 节 。 可 以 进 行 算 术 运 算 (+, -, /, *, ^)、 比 较 、 赋 值 、div、mod、quot 及 rem<br />
操 作 。 值 的 范 围 是 0 到 4294967295。 它 的 表 示 方 法 同 integer, 只 是 不 能 使 用 负 号 。<br />
unsigned64<br />
无 符 号 整 数 。<br />
unsigned64<br />
这 个 域 的 值 占 八 个 字 节 。 值 的 范 围 是 0 到 2^64-1 = 18,446,744,073,709,551,615。 它 的 表 示<br />
方 法 同 integer64, 只 是 不 能 使 用 负 号 。 可 以 进 行 的 操 作 同 unsigned。<br />
89
eal<br />
浮 点 数 ( 实 数 )。<br />
real<br />
这 个 域 的 值 占 八 个 字 节 。 这 个 域 只 是 为 了 方 便 用 户 引 入 的 , 可 以 进 行 所 有 的 算 术 、 赋 值 及 比 较 操 作 。<br />
它 的 值 范 围 是 -1.7e+308 到 1.7e+308。 需 要 的 时 候 , 整 数 域 的 值 会 自 动 地 转 换 成 实 数 域 的 值 。 它 的 文<br />
字 表 示 方 法 由 Real 规 则 确 定 :<br />
Real :<br />
Add_operation-opt Fraction Exponent-opt<br />
Fraction :<br />
Dec_number Fractional_part-opt<br />
Fractional_part :<br />
. Dec_number<br />
Exponent :<br />
Exp Add_operation-opt Dec_number<br />
Exp :<br />
e<br />
E<br />
Add_operation :<br />
+<br />
-<br />
Dec_number :<br />
Dec_digit-list<br />
Dec_digit : one of<br />
0 1 2 3 4 5 6 7 8 9<br />
real32<br />
浮 点 数 。<br />
real32<br />
这 个 域 的 值 占 四 个 字 节 。 它 只 是 为 了 用 户 的 方 便 而 引 入 的 , 可 以 进 行 所 有 的 算 术 、 赋 值 及 比 较 操 作 。<br />
它 的 值 范 围 是 -3.4e+38 到 3.4e+38。 表 示 方 法 同 real。<br />
pointer<br />
内 存 地 址 的 指 针 。<br />
pointer<br />
指 针 直 接 对 应 于 内 存 地 址 , 只 能 进 行 相 等 操 作 。 这 个 类 型 中 有 一 个 内 建 的 常 数 null。<br />
handle<br />
handle( 句 柄 ) 用 于 Windows API 类 函 数 调 用 , 它 占 四 个 字 节 , 不 能 对 它 进 行 什 么 操 作 , 也 不 能 从<br />
别 的 域 转 换 来 或 转 换 到 别 的 域 ( 除 非 是 uncheckedConvert)。 这 个 类 型 中 有 内 建 的 常 数 nullHandle 及<br />
90
invalidHandle。<br />
boolean<br />
布 尔 值 。<br />
boolean<br />
这 个 域 只 是 为 了 用 户 方 便 而 引 入 的 , 它 可 以 看 成 如 下 定 义 的 复 合 域 :<br />
domains<br />
boolean = false(); true().<br />
factDB<br />
命 名 了 的 内 部 数 据 库 描 述 符 。<br />
factDB<br />
这 个 域 有 如 下 隐 含 的 元 声 明 :<br />
domains<br />
factDB = struct @factdb( named_internal_database_domain, object ).<br />
事 实 段 中 所 有 用 户 定 义 的 名 称 都 是 这 个 域 的 常 数 。 需 要 时 , 编 译 器 自 动 地 从 这 些 常 数 中 构 建 相 应 的 复<br />
合 项 。 在 运 行 时 , 这 个 结 构 的 第 一 项 含 有 相 应 域 描 述 符 的 地 址 而 第 二 项 或 是 零 ( 对 类 事 实 段 ) 或 是 一 个 对<br />
象 的 指 针 ( 即 This, 对 对 象 事 实 段 )。<br />
谓 词<br />
assert/1<br />
asserta/1<br />
assertz/1<br />
bound/1 determ<br />
class_Name/0-><br />
compare/2-><br />
convert/2-><br />
digitsOf/1-><br />
errorExit/1 erroneous<br />
fail/0 failure<br />
free/1 determ<br />
hasDomain/2<br />
isErroneous/1 determ<br />
lowerBound/1-><br />
maxDigits/1-><br />
not/1 determ<br />
在 相 应 内 部 数 据 库 的 末 尾 插 入 指 定 的 事 实<br />
在 相 应 内 部 数 据 库 的 最 前 面 插 入 指 定 的 事 实<br />
在 相 应 内 部 数 据 库 的 末 尾 插 入 指 定 的 事 实<br />
测 试 指 定 变 量 是 否 已 经 绑 定<br />
这 个 编 译 时 的 谓 词 返 回 代 表 当 前 接 口 或 类 的 名 称 的 串<br />
返 回 变 量 比 较 的 结 果<br />
有 核 查 的 项 转 换<br />
返 回 指 定 实 数 域 的 精 度<br />
以 指 定 的 返 回 代 码 ErrorNumber 完 成 一 次 运 行 时 错 误 , 并 设 置 内 部 错 误 消 息<br />
引 发 回 溯<br />
检 查 一 个 变 量 是 否 是 自 由 的<br />
检 查 一 个 变 量 是 否 是 指 定 域 的<br />
检 查 事 实 变 量 是 否 为 erroneous 的<br />
返 回 指 定 数 字 域 的 下 界 值<br />
获 取 相 应 实 数 域 的 精 度 值<br />
子 目 标 结 果 (success/fail) 取 非<br />
91
predicate_fullname/0-><br />
predicate name/0-><br />
retract/1 nondeterm<br />
retractall/1<br />
retractFactDb/1<br />
sizeBitsOf/1-><br />
sizeOf/1-><br />
sizeOfDomain/1-><br />
sourcefile lineno/0-><br />
sourcefile_name/0-><br />
sourcefile_timestamp/0-><br />
succeed/0<br />
toBinary/1-><br />
toBoolean/1-><br />
toString/1-><br />
toTerm/1-><br />
tryToTerm/1-><br />
tryConvert/2-> determ<br />
uncheckedConvert/2-><br />
upperBound/1-><br />
返 回 调 用 这 个 谓 词 的 谓 词 全 称<br />
返 回 调 用 这 个 谓 词 的 谓 词 名<br />
由 相 应 内 部 数 据 库 中 删 除 相 应 的 事 实<br />
由 相 应 内 部 数 据 库 中 删 除 所 有 相 应 的 事 实<br />
由 相 应 内 部 数 据 库 中 删 除 所 有 事 实<br />
获 取 指 定 域 的 实 体 所 占 内 存 的 比 特 数<br />
获 取 指 定 项 所 占 内 存 的 字 节 数<br />
获 取 指 定 域 的 实 体 所 占 内 存 的 字 节 数<br />
返 回 编 译 器 处 理 的 源 文 件 的 当 前 行 号<br />
返 回 编 译 器 处 理 的 源 文 件 名<br />
返 回 表 示 编 译 器 处 理 的 源 文 件 时 间 的 串<br />
该 谓 词 总 是 成 功<br />
将 指 定 的 项 转 换 成 二 进 制 表 示<br />
这 个 元 谓 词 的 目 标 是 要 把 ( 对 一 个 谓 词 或 事 实 的 ) 确 定 性 的 调 用 转 换 成<br />
procedure 的 , 返 回 boolean 域 的 值 。<br />
将 指 定 的 项 转 换 成 串 表 示<br />
将 指 定 的 串 / 二 进 制 表 示 项 转 换 为 相 应 域 的 返 回 值 变 量 的 <strong>Prolog</strong> 的 项<br />
将 指 定 的 串 / 二 进 制 表 示 项 转 换 为 相 应 域 的 返 回 值 变 量 的 <strong>Prolog</strong> 的 项<br />
核 查 输 入 项 能 否 被 严 格 地 转 换 为 指 定 域 的 项 , 返 回 转 换 后 的 项<br />
没 有 核 查 的 域 转 换<br />
返 回 指 定 数 字 域 的 上 界 值<br />
下 面 的 谓 词 已 经 不 再 使 用 :<br />
finally/2<br />
findall/3<br />
trap/3 determ<br />
用 try ... finally ... end try 替 代<br />
用 述 求 表 [ ... || ... ] 替 代<br />
用 try ... catch V do ... end try 替 代<br />
assert/1<br />
assert : ( FactTerm).<br />
assert(Fact) 把 指 定 的 事 实 Fact 插 入 到 相 应 的 内 部 事 实 数 据 库 的 最 后 面 。Fact 必 须 是 属 于 内 部 事 实<br />
数 据 库 域 的 一 个 项 。(assert/1 applied to a single fact changes the existing instance of a fact to<br />
the specified one.), 它 与 assertz/1 效 果 是 一 样 的 。 还 可 以 参 看 asserta/1。<br />
注 意 ,retract/1 和 assert/1 两 者 的 如 下 组 合 会 导 致 死 循 环 :<br />
loop() :-<br />
retract(fct(X)),<br />
... % 由 X 建 立 Y<br />
assert(fct(Y)),<br />
fail.<br />
问 题 在 于 , 在 第 一 行 的 retract 将 最 后 删 除 插 入 到 最 后 一 行 的 事 实 , 因 为 在 事 实 链 中 它 是 最 后 插 入 的 。<br />
异 常<br />
插 入 一 个 声 明 为 determ 的 事 实 , 而 那 个 事 实 实 例 已 经 存 在 了 。<br />
92
asserta/1<br />
asserta : ( FactTerm).<br />
插 入 一 个 事 实 到 相 应 内 部 数 据 库 的 最 前 面 。<br />
描 述<br />
asserta(Fact) 把 指 定 的 事 实 Fact 插 入 到 相 应 的 内 部 事 实 数 据 库 的 最 前 面 。Fact 必 须 是 属 于 内 部 事<br />
实 数 据 库 域 的 一 个 项 。(asserta/1 applied to a single fact changes the existing instance of a fact<br />
to the specified one.)。 可 以 参 看 assert/1 和 assertz/1。<br />
异 常<br />
插 入 一 个 声 明 为 determ 的 事 实 , 而 那 个 事 实 实 例 已 经 存 在 了 。<br />
assertz/1<br />
assertz : ( FactTerm).<br />
assertz 与 assert/1 谓 词 完 全 一 样 。<br />
bound/1<br />
bound : ( Variable) determ.<br />
测 试 指 定 的 变 量 是 否 已 经 绑 定 了 一 个 值 。<br />
描 述<br />
如 果 Variable 已 经 被 绑 定 ,bound(Variable) 成 功 , 反 之 则 失 败 。 谓 词 用 于 控 制 流 样 式 以 及 检 查 引<br />
用 的 变 量 绑 定 情 况 , 如 果 Variable 的 任 意 一 部 分 已 经 实 例 化 了 , 都 将 视 为 已 经 绑 定<br />
参 看 free/1。<br />
class_Name/0-><br />
class_Name : () -> string ClassName.<br />
这 个 编 译 时 谓 词 返 回 一 个 串 , 这 个 串 是 当 前 接 口 或 类 的 名 称 。<br />
compare/2-><br />
compare : (A Left, A Right) -> compareResult CompareResult.<br />
对 相 同 域 的 两 个 项 进 行 比 较 。 这 里 的 CompareResult 是 compareResult 域 的 结 果 变 量 。<br />
例<br />
CompareResult = compare("123","abc")<br />
convert/2-><br />
convert : ( Type, Term) -> Converted.<br />
有 核 查 的 项 转 换 。<br />
93
描 述<br />
这 个 函 数 的 调 用 模 板 是 :<br />
ReturnTerm = convert(returnDomain, InputTerm)<br />
参 数 :<br />
returnDomain: 指 定 要 将 InputTerm 转 换 到 该 域 , 它 必 须 是 内 建 的 <strong>Visual</strong> <strong>Prolog</strong> 域 或 接 口 域 的 名 称 ,<br />
或 是 用 户 定 义 的 与 内 建 的 <strong>Visual</strong> <strong>Prolog</strong> 域 、 数 字 域 、 二 进 制 域 、 指 针 域 同 义 的 名 称 。 这 个 名 称 在 编 译 时 必 须 是<br />
确 定 的 , 也 就 是 说 , 不 能 用 变 量 来 表 示 。<br />
InputTerm: 指 定 要 转 换 的 值 , 它 可 以 是 任 意 <strong>Prolog</strong> 项 或 表 达 式 。 如 果 是 表 达 式 , 在 转 换 时 应 有 明<br />
确 的 计 算 结 果 。<br />
ReturnTerm: 返 回 参 数 ReturnTerm 是 returnDomain 类 型 的 。<br />
备 注<br />
谓 词 convert 把 InputTerm 彻 底 转 换 到 指 定 的 returnDomain 域 , 返 回 新 的 项 ReturnTerm。 如 果<br />
它 不 能 完 成 要 求 的 转 换 , 就 会 产 生 一 个 错 误 。 还 有 一 个 功 能 上 相 似 的 谓 词 tryConvert/2->, 但 这 个 谓 词 如<br />
果 完 成 不 了 指 定 的 转 换 就 只 是 失 败 , 不 会 产 生 任 何 运 行 时 错 误 。<br />
允 许 的 转 换 :<br />
• 数 字 域 间 ;<br />
• 接 口 类 型 间 ;<br />
• string 和 symbol 间 ;<br />
• 从 binary 转 换 到 pointer;<br />
• 上 述 各 项 的 同 义 域 间 ;<br />
• reference 域 间 及 相 应 的 non-reference 域 间 。<br />
与 谓 词 uncheckedConvert/2-> 对 比 一 下 ,uncheckedConvert/2-> 可 以 对 两 个 项 进 行 非 核 查 的 转<br />
换 , 对 域 的 类 型 没 有 规 定 , 只 要 这 两 个 域 的 比 特 位 长 短 一 样 就 行 。<br />
当 编 译 时 对 源 及 目 标 域 静 态 已 知 的 情 况 下 ,convert/2->( 或 tryConvert/2->) 谓 词 进 行 一 个 有 核<br />
查 的 显 式 的 转 换 。 这 种 显 式 转 换 的 结 果 是 下 列 情 况 之 一 :<br />
• ok- 成 功 转 换 到 目 标 域 ;<br />
• run-time-check- 转 换 到 目 标 域 , 但 带 有 一 个 运 行 时 兼 容 性 的 核 查 ;<br />
• error- 不 可 能 转 换 , 产 生 错 误 。<br />
带 核 查 的 显 式 转 换 规 则 :<br />
• 同 义 域 使 用 相 应 的 域 本 身 转 换 的 规 则 ;<br />
• 数 字 域 只 能 转 换 为 数 字 域 ;<br />
• 匿 名 整 数 域 [const .. const] 由 整 数 常 数 代 表 ;<br />
• 匿 名 实 数 域 digits dig [const.. const] 由 实 数 常 数 代 表 , 这 里 的 是 尾 数 中 去 掉 无 意 义 的 零 后<br />
的 数 字 位 数 ;<br />
• symbol 域 和 string 域 的 值 可 以 相 互 转 换 ;<br />
• binary 域 的 值 可 以 转 换 为 pointer 域 ;<br />
• 对 接 口 隐 含 引 入 的 域 只 能 按 下 面 要 介 绍 的 规 则 转 换 到 该 接 口 域 ;<br />
• 其 它 的 域 间 不 能 转 换 。<br />
94
数 字 域 间 的 转 换 :<br />
这 种 转 换 首 先 要 考 虑 数 值 的 范 围 , 如 果 源 的 范 围 与 目 标 的 不 重 合 , 就 会 产 生 错 误 ; 而 如 果 只 是 部 分 重<br />
合 , 就 会 有 运 行 时 的 核 查 。 还 有 , 如 果 一 个 是 整 数 域 一 个 是 实 数 域 , 就 要 在 比 较 前 把 整 数 范 围 转 换 成 实 数<br />
范 围 。<br />
如 果 输 入 项 是 实 数 而 输 出 项 是 整 数 ,convert/2-> 及 tryConvert/2-> 谓 词 就 会 把 输 入 值 截 断 成 最 接<br />
近 零 的 近 似 整 数 值 。<br />
接 口 类 型 的 转 换<br />
谓 词 convert/2-> 允 许 把 任 意 对 象 转 换 成 任 意 接 口 类 型 的 , 而 这 种 转 换 的 实 际 正 确 性 在 运 行 时 作 核<br />
查 。 当 创 建 一 个 对 象 时 , 保 存 了 它 的 类 型 , 因 而 这 个 对 象 作 为 参 数 传 递 时 它 是 知 道 自 己 原 来 的 类 型 的 , 这<br />
个 原 来 的 类 型 可 以 用 来 核 查 允 许 的 转 换 。 例 如 :<br />
interface x<br />
supports a, b<br />
end interface x<br />
如 果 对 象 是 由 实 现 接 口 x 的 类 创 建 的 , 而 后 对 象 又 以 类 型 a 的 参 数 传 递 给 某 个 谓 词 , 那 么 就 允 许 转 换 这<br />
个 对 象 到 类 型 b。<br />
异 常<br />
• 核 查 范 围 出 错 ;<br />
• 不 支 持 的 接 口 类 型 。<br />
digitsOf/1-><br />
digitsOf : ( Domain) -> unsigned.<br />
返 回 实 数 域 表 示 的 精 度 。<br />
描 述<br />
这 个 函 数 的 调 用 模 板 是 :<br />
Precision = digitsof(domainName)<br />
这 个 编 译 时 谓 词 的 输 入 参 数 domainName 是 一 个 实 数 域 , 编 译 时 domainName 应 该 是 明 确 的 ( 也 就<br />
是 说 它 不 能 来 自 变 量 )。 谓 词 返 回 的 Precision 数 值 由 该 域 声 明 中 的 digits 属 性 确 定 。<br />
编 译 器 保 证 domainName 域 的 值 至 少 具 有 Precision 个 有 效 十 进 制 位 数 。<br />
errorExit/1<br />
errorExit : (unsigned ErrorNumber) erroneous.<br />
以 指 定 的 返 回 代 码 ErrorNumber 完 成 一 次 运 行 时 错 误 , 错 误 代 码 可 以 用 在 try-catch-finally 中 。<br />
fail/0<br />
fail : () failure.<br />
95
引 起 回 溯 。<br />
描 述<br />
fail 谓 词 强 迫 一 个 谓 词 失 败 , 因 而 总 是 引 起 回 溯 。 一 个 以 fail 结 尾 的 子 句 , 无 法 为 子 句 绑 定 输 出 参 数 。<br />
free/1<br />
free : ( Variable) determ.<br />
检 查 一 个 变 量 是 否 为 自 由 的 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
free(Variable)<br />
如 果 指 定 的 变 量 Variable 是 自 由 的 ,free 这 个 谓 词 就 成 功 , 而 如 果 Variable 是 绑 定 的 , 则 失 败 。 如<br />
果 Variable 的 任 意 部 分 实 例 化 了 ,free 谓 词 将 认 为 它 是 绑 定 的 。<br />
参 看 bound/1。<br />
hasDomain/2<br />
hasDomain : ( Type, Variable) procedure.<br />
检 查 变 量 VariableName 的 域 名 是 否 为 domainName。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
hasDomain(domainName, VariableName)<br />
谓 词 声 明 VariableName 属 于 参 数 domainName 说 明 的 域 。domainName 参 数 应 当 是 一 个 标 准 的 或<br />
用 户 定 义 的 域 的 名 称 , 这 个 域 名 在 编 译 时 应 该 是 确 定 的 ( 也 就 是 说 不 能 来 自 一 个 变 量 )。<br />
lowerBound/1-><br />
lowerBound : ( NumericDomain) -> LowerBound.<br />
返 回 指 定 的 NumericDomain 域 的 下 限 值 LowerBound。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
LowerBoundValue = lowerBound(domainName)<br />
这 是 一 个 编 译 时 谓 词 , 它 返 回 指 定 的 数 字 域 domainName 的 下 限 值 LowerBoundValue, 这 个 值 也<br />
是 domainName 域 的 。 域 名 domainName 在 编 译 时 应 该 是 确 定 的 ( 也 就 是 说 不 能 来 自 一 个 变 量 )。<br />
参 看 upperBound/1->。<br />
96
异 常<br />
如 果 指 定 的 domainName 域 不 是 数 字 域 , 编 译 时 会 出 错 。<br />
isErroneous/1<br />
isErroneous : ( FactVariable) determ.<br />
如 果 指 定 的 事 实 变 量 是 erroneous 的 , 这 个 谓 词 就 成 功 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
isErroneous(factVariableName)<br />
如 果 指 定 的 事 实 变 量 factVariableName 具 有 erroneous 的 值 , 这 个 谓 词 就 会 成 功 , 否 则 就 失 败 。<br />
maxDigits/1-><br />
maxDigits : ( RealDomain) -> unsigned MaxDigits<br />
获 取 相 应 于 domainName 指 定 的 实 数 域 的 精 度 值 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
MaxDigitsNumber = maxdigits(domainName)<br />
返 回 对 应 domainName 参 数 的 最 大 位 数 MaxDigitsNumber。domainName 应 该 是 real 域 名 。<br />
not/1<br />
not : ( SubGoal) determ.<br />
如 果 SubGoal 失 败 则 该 谓 词 成 功 , 反 之 则 失 败<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
not(SubGoal)<br />
求 值 时 , 如 果 SubGoal 失 败 , 则 not 成 功 。 注 意 ,SubGoal 无 法 绑 定 任 何 变 量 , 因 为 只 有 当 SubGoal<br />
失 败 not(SubGoal) 才 能 成 功 ( 而 失 败 的 目 标 无 法 绑 定 任 何 东 西 )。<br />
predicate_fullname/0-><br />
predicate_fullname : () -> string PredicateFullName.<br />
这 个 谓 词 返 回 调 用 它 的 谓 词 全 称 PredicateFullName, 全 称 中 带 有 范 围 名 称 的 限 定 。<br />
97
描 述<br />
谓 词 predicate_fullname 只 能 用 在 一 个 谓 词 定 义 的 子 句 体 中 , 如 果 在 其 它 的 地 方 使 用 这 个 谓 词 , 会<br />
在 编 译 时 出 错 。 参 看 predicate_name。<br />
predicate_name/0-><br />
predicate_name : () -> string PredicateName.<br />
这 个 谓 词 返 回 调 用 它 的 谓 词 名 称 PredicateName。<br />
描 述<br />
谓 词 predicate_fullname 只 能 用 在 一 个 谓 词 定 义 的 子 句 体 中 , 如 果 在 其 它 的 地 方 使 用 这 个 谓 词 , 会<br />
在 编 译 时 出 错 。 参 看 predicate_fullname。<br />
retract/1<br />
retract : ( FactTerm) nondeterm anyfow.<br />
从 事 实 数 据 库 中 删 除 了 第 一 个 匹 配 的 事 实 时 成 功 , 如 果 没 有 匹 配 的 事 实 则 失 败 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
retract(FactTemplate)<br />
这 里 的 FactTemplate 应 该 是 一 个 事 实 项 。retract/1 谓 词 从 相 应 的 事 实 数 据 库 中 删 除 第 一 个 匹 配 的<br />
FactTemplate; 通 过 回 溯 还 可 以 删 除 剩 余 的 匹 配 事 实 。<br />
注 意 ,FactTemplate 可 以 是 实 例 的 任 意 层 级 , 它 是 与 事 实 数 据 库 中 的 事 实 匹 配 , 这 意 味 着 所 有 自 由<br />
变 量 在 retract/1 调 用 时 都 会 被 绑 定 。<br />
FactTemplate 可 以 有 任 意 个 匿 名 变 量 , 也 就 是 变 量 名 可 以 仅 是 一 个 下 划 线 或 以 一 个 下 划 线 开 头 的 变<br />
量 名 , 只 要 是 这 个 变 量 在 子 句 中 只 出 现 一 次 。 例 如 :<br />
retract(person("Hans", _Age)),<br />
它 会 删 除 第 一 个 匹 配 的 事 实 , 这 个 事 实 的 第 一 个 参 数 是 “Hans” 而 第 二 个 参 数 可 以 是 任 意 的 。<br />
当 删 除 的 事 实 声 明 是 determ 的 时 , 对 retract/1 的 调 用 将 是 确 定 性 的 。<br />
参 看 retractall/1 和 retractFactDb。<br />
提 示<br />
retract/1 谓 词 不 能 应 用 于 single 事 实 或 事 实 变 量 。<br />
如 果 在 工 程 当 前 范 围 中 声 明 了 single 事 实 , 以 自 由 的 FactTemplate 变 量 调 用 retract/1 时 要 特 别 小<br />
心 。 要 是 对 single 事 实 做 retract, 会 产 生 运 行 时 错 误 。<br />
在 没 有 匹 配 的 事 实 时 ,retract/1 谓 词 失 败 。<br />
retractall/1<br />
retractall : ( FactTerm) .<br />
98
从 事 实 数 据 库 中 删 除 所 有 匹 配 的 事 实 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
retractall(FactTemplate)<br />
FactTemplate 应 是 一 个 事 实 项 。<br />
retractall/1 删 除 所 有 与 给 定 的 FactTemplate 匹 配 的 事 实 ( 在 未 命 名 的 事 实 数 据 库 中 是 事 实 数 据 库<br />
谓 词 for facts database predicates in unnamed facts databases)。 它 总 是 成 功 , 即 使 没 有 删 除 什 么<br />
事 实 时 也 会 成 功 。<br />
注 意 , 因 为 不 可 能 删 除 single 事 实 , 所 以 这 个 谓 词 不 会 删 除 在 未 命 名 事 实 数 据 库 中 匹 配 的 single 事 实<br />
或 事 实 变 量 。 不 过 , 如 果 编 译 时 编 译 器 发 现 匹 配 的 事 实 只 有 一 些 single 事 实 , 就 会 产 生 编 译 时 的 错 误 。<br />
由 retractall/1 不 可 能 得 到 任 何 输 出 值 , 因 此 , 调 用 时 所 有 变 量 必 须 都 是 绑 定 的 或 是 单 个 下 划 线 ( 匿<br />
名 的 )。 注 意 ,FactTemplate 可 以 是 实 例 的 任 意 层 级 , 但 自 由 变 量 必 须 是 单 个 下 划 线 ( 无 条 件 匿 名 ),<br />
与 retract/1 不 同 , 以 下 划 线 开 头 的 条 件 匿 名 变 量 ( 如 _AnyValue) 不 能 在 retractall/1 中 使 用 。<br />
参 看 retract/1 和 retractFactDb/1。<br />
retractFactDb/1<br />
retractFactDb : (factDB FactDB).<br />
从 命 名 的 内 部 事 实 数 据 库 FactDB 中 删 除 所 有 的 事 实 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
retractFactDb(FactDB)<br />
retractFactDb/1 从 命 名 的 内 部 事 实 数 据 库 FactDB 中 删 除 所 有 的 事 实 。 注 意 , 对 single 的 事 实 或<br />
事 实 变 量 仍 会 原 样 保 留 下 来 。 参 看 retractall/1 和 retract/1。<br />
retractall/2<br />
废 弃 的 谓 词 ! 用 retractFactDb/1 替 代 。<br />
sizeBitsOf/1-><br />
sizeBitsOf : ( DomainName) -> unsigned BitSize.<br />
获 取 指 定 域 DomainName 的 实 体 在 内 存 中 占 用 的 比 特 位 数 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
BitSize = sizeBitsOf(DomainName)<br />
这 个 编 译 时 谓 词 以 域 DomainName 为 输 入 参 数 , 返 回 该 域 的 实 体 占 用 内 存 的 大 小 , 结 果 以 比 特 位 计 。<br />
99
对 整 数 域 sizeBitsOf/1-> 返 回 的 值 是 域 声 明 中 的 size 字 段 的 定 义 值 。 对 整 数 域 来 说 , 下 面 的 关 系 总<br />
是 成 立 的 :<br />
sizeOfDomain(domain)*8 - 7 <br />
sizeOf : ( Term) -> unsigned ByteSize.<br />
获 取 指 定 项 Term 占 用 的 内 存 字 节 数 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
ByteSize = sizeOf(Term)<br />
sizeOf/1-> 函 数 以 一 个 项 为 输 入 参 数 , 返 回 Term 项 占 用 内 存 的 字 节 数 ByteSize, 这 个 值 是 无 符 号<br />
整 数 值 。<br />
sizeOfDomain/1-><br />
sizeOfDomain : ( DomainName) -> unsigned ByteSize.<br />
获 取 指 定 域 DomainName 的 实 体 在 内 存 中 占 用 的 字 节 数 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
ByteSize = sizeOfDomain(DomainName)<br />
这 个 编 译 时 谓 词 以 域 DomainName 为 输 入 参 数 , 返 回 该 域 的 实 体 占 用 内 存 的 大 小 , 结 果 以 字 节 计 ,<br />
ByteSize 的 值 是 无 符 号 整 数 域 的 。 可 以 对 比 一 下 sizeBitsOf/1->, 在 它 那 里 以 比 特 计 算 大 小 。<br />
sourcefile_lineno/0-><br />
sourcefile_lineno : () -> unsigned LineNumber.<br />
返 回 编 译 器 处 理 的 源 文 件 的 当 前 行 号 。<br />
描 述<br />
这 个 编 译 时 谓 词 返 回 编 译 器 正 在 处 理 的 源 文 件 的 当 前 行 号 。<br />
sourcefile_name/0-><br />
sourcefile_name : () -> string FileName.<br />
返 回 编 译 器 处 理 的 源 文 件 名 。<br />
100
描 述<br />
这 个 编 译 时 谓 词 返 回 表 示 编 译 器 正 在 处 理 的 源 文 件 名 的 串 。<br />
sourcefile_timestamp/0-><br />
sourcefile_timestamp : () -> string TimeStamp..<br />
返 回 表 示 编 译 器 处 理 的 源 文 件 日 期 时 间 的 串 。<br />
描 述<br />
这 个 编 译 时 谓 词 按 YYYY-MM-DD HH:MM:SS 格 式 返 回 表 示 编 译 器 正 在 处 理 的 源 文 件 日 期 时 间 的<br />
串 , 格 式 中 :<br />
YYYY – 年<br />
MM – 月<br />
DD – 日<br />
HH – 小 时<br />
MM – 分 钟<br />
SS – 秒<br />
succeed/0<br />
succeed : ().<br />
谓 词 succeed/0 总 是 成 功 。<br />
描 述<br />
标 准 谓 词 succeed/0 明 确 地 成 功 一 次 。<br />
toBinary/1-><br />
toBinary : (Term) -> binary Serialized.<br />
将 项 Term 转 换 成 binary 表 示 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
Serialized = toBinary(Term)<br />
当 ( 某 个 域 domainName) 的 项 Term 转 换 成 二 进 制 项 时 , 可 以 安 全 地 存 储 在 文 件 中 或 是 在 网 络 上 传<br />
给 另 一 个 程 序 。 以 后 这 个 二 进 制 项 值 Serialized 还 可 以 用 函 数 toTerm/1-> 转 换 回 <strong>Visual</strong> <strong>Prolog</strong> 项 ( 反<br />
转 项 的 域 要 适 合 于 domainName)。<br />
toBoolean/1-><br />
toBoolean : ( SubGoal) -> boolean Succeed.<br />
101
这 个 元 谓 词 的 目 标 是 要 把 ( 对 一 个 谓 词 或 事 实 的 ) 确 定 性 的 调 用 转 换 成 procedure 的 , 返 回 boolean<br />
域 的 值 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
True_or_False = toBoolean(deterministic_call)<br />
元 谓 词 toBoolean/1-> 返 回 boolean 值 。 如 果 确 定 性 调 用 成 功 则 返 回 结 果 是 true, 如 果 确 定 性 调 用<br />
失 败 返 回 结 果 是 false。<br />
toString/1-><br />
toString : (Term) -> string Serialized.<br />
将 指 定 的 项 Term 转 换 为 串 表 示 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
Serialized = toString(Term)<br />
当 ( 某 个 域 的 )Term 项 转 换 成 一 个 串 时 , 它 可 以 安 全 地 保 存 在 文 件 中 或 是 经 网 络 传 送 给 另 外 的 程 序 。<br />
以 后 串 值 还 可 以 用 函 数 toTerm/1-> 转 换 回 <strong>Visual</strong> <strong>Prolog</strong> 项 ( 反 转 项 的 域 要 适 合 于 domainName)。<br />
toTerm/1-><br />
toTerm : (string Serialized) -> Term.<br />
toTerm : (binary Serialized) -> Term.<br />
将 指 定 的 项 Serialized 的 串 / 二 进 制 表 示 转 换 为 相 应 域 的 返 回 值 变 量 的 <strong>Prolog</strong> 的 Term。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
Term = toTerm(Serialized)<br />
在 编 译 时 , 编 译 器 可 以 确 定 返 回 值 Term 的 域 。 要 注 意 , 二 进 制 版 的 toTerm 谓 词 几 乎 是 逐 字 节 地 做<br />
转 换 , 并 且 只 检 查 返 回 值 Term 的 域 所 要 求 的 与 Serialized 数 据 的 兼 容 性 。 保 证 提 供 的 Serialized 二 进 制<br />
数 可 以 正 确 地 转 换 到 期 望 的 域 是 程 序 员 的 事 情 。<br />
toTerm 谓 词 与 toBinary/1-> 和 toString/1-> 谓 词 是 配 套 的 , 当 ( 某 个 域 的 )Term 项 由 toBinary/1-><br />
或 toString/1-> 转 换 成 一 个 二 进 制 或 串 的 Serialized 时 , 它 可 以 安 全 地 保 存 在 文 件 中 或 是 经 网 络 传 送 给 另<br />
外 的 程 序 。 以 后 用 对 应 的 函 数 toTerm/1-> 还 可 以 把 这 个 串 / 二 进 制 值 Serialized 转 换 回 <strong>Visual</strong> <strong>Prolog</strong><br />
的 项 Term。 为 正 确 地 反 转 项 , 子 句 变 量 Term 的 域 要 适 合 于 原 来 的 域 domainName。<br />
参 看 tryToTerm。<br />
异 常<br />
如 果 编 译 时 编 译 器 不 能 确 定 返 回 值 的 域 , 则 出 现 编 译 时 错 误 。<br />
102
当 toTerm/1-> 谓 词 不 能 转 换 串 或 二 进 制 项 为 指 定 域 的 项 时 , 会 产 生 运 行 时 错 误 。<br />
tryToTerm/1-><br />
tryToTerm : (string Serialized)-> Term determ.<br />
tryToTerm : (binary Serialized)-> Term determ.<br />
如 同 toTerm 一 样 , 转 换 相 应 的 串 或 二 进 制 表 示 的 Serialized 为 项 Term, 它 们 之 间 的 差 别 是 : 谓 词<br />
tryToTerm 如 果 不 能 把 相 应 的 串 或 二 进 制 项 转 换 为 指 定 域 的 项 时 就 失 败 , 而 toTerm 谓 词 则 会 产 生 异 常 。<br />
参 看 toTerm。<br />
tryConvert/2-><br />
tryConvert : ( Type, Value) determ -> Converted determ.<br />
核 查 输 入 项 Value 能 否 被 严 格 地 转 换 为 指 定 域 Type 的 项 , 返 回 转 换 后 的 项 Converted。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
ReturnTerm = tryConvert(returnDomain, InputTerm)<br />
参 数 :<br />
returnDomain: 规 定 tryConvert/2-> 谓 词 尝 试 将 指 定 项 InputTerm 转 换 到 该 域 , 它 可 以 是 当 前<br />
范 围 可 访 问 的 任 何 域 。 域 名 returnDomain 在 编 译 时 必 须 是 确 定 的 , 即 不 能 来 自 于 变 量 。<br />
InputTerm: 要 转 换 的 项 , 它 可 以 是 任 意 <strong>Prolog</strong> 项 或 表 达 式 , 如 果 是 表 达 式 , 转 换 前 要 求 值 。<br />
ReturnTerm: 返 回 的 项 , 它 是 returnDomai 域 的 。<br />
备 注<br />
转 换 规 则 tryConvert/2-> 与 内 含 谓 词 convert/2-> 是 一 样 的 , 但 convert/2-> 产 生 转 换 错 误 时 , 同<br />
样 条 件 下 的 tryConvert/2-> 会 是 失 败 。<br />
如 果 相 应 的 转 换 成 功 则 这 个 谓 词 成 功 , 反 之 它 就 失 败 。 该 谓 词 尝 试 把 InputTerm 彻 底 转 换 到 指 定 的<br />
returnDomain 域 , 若 它 不 能 完 成 要 求 的 转 换 , 就 会 失 败 。 当 tryConvert/2-> 谓 词 成 功 时 , 它 会 返 回 转<br />
换 到 指 定 域 returnDomain 的 项 ReturnTerm。<br />
允 许 的 转 换 及 规 则 请 参 看 带 核 查 的 显 式 转 换 谓 词 convert/2->。 还 可 参 看 uncheckedConvert/2->。<br />
uncheckedConvert/2-><br />
uncheckedConvert : ( Type, Value) -> Converted.<br />
将 值 转 换 为 另 一 个 类 型 , 不 带 核 查 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
ReturnTerm = uncheckedConvert(returnDomain, InputTerm)<br />
参 数 :<br />
103
eturnDomain: 指 定 uncheckedConvert 要 将 InputTerm 非 安 全 性 地 转 换 到 该 域 , 它 可 以 是 当 前 范<br />
围 能 够 访 问 的 任 何 域 。ReturnTerm 和 InputTerm 的 比 特 位 的 长 短 应 该 是 一 样 的 。 域 名 称 returnDomain<br />
在 编 译 时 必 须 是 确 定 的 , 也 就 是 说 , 不 能 用 变 量 来 表 示 。<br />
InputTerm: 指 定 要 转 换 的 值 , 它 可 以 是 任 意 <strong>Prolog</strong> 项 或 表 达 式 。 如 果 是 表 达 式 , 在 转 换 前 先 要 求<br />
值 。<br />
ReturnTerm: 返 回 参 数 ReturnTerm 是 returnDomain 类 型 的 。<br />
备 注<br />
uncheckedConvert 谓 词 进 行 一 个 很 武 断 的 转 换 。 它 对 InputTerm 进 行 预 求 值 ( 如 果 它 是 一 个 表<br />
达 式 的 话 ), 将 其 当 前 的 类 型 转 换 到 returnDomain 的 类 型 并 与 ReturnTerm 合 一 。 它 在 运 行 时 不 做 核 查 ,<br />
所 以 差 不 多 任 何 项 都 可 以 很 莽 撞 地 转 换 为 别 的 类 型 。 因 而 , 不 正 确 地 使 用 它 可 能 会 导 致 很 糟 糕 的 结 果 , 一<br />
定 要 小 心 ! 强 烈 建 议 , 只 要 可 能 就 避 免 使 用 它 而 代 之 以 convert/2-> 和 tryConvert/2->。 不 过 , 当 对 象 是<br />
由 COM 系 统 返 回 的 时 候 , 需 要 用 uncheckedConvert 来 进 行 转 换 , 因 为 <strong>Prolog</strong> 程 序 没 有 关 于 它 的 实 际 类<br />
型 的 信 息 。<br />
upperBound/1-><br />
upperBound : ( NumericDomain) -> UpperBound.<br />
返 回 指 定 数 字 域 的 上 限 值 。<br />
描 述<br />
这 个 谓 词 的 调 用 模 板 是 :<br />
UpperBound = upperBound(domainName)<br />
upperBound 是 一 个 编 译 时 谓 词 , 它 返 回 指 定 数 字 域 domainName 的 上 限 值 。upperBound 谓 词 返<br />
回 的 值 UpperBound 也 是 domainName 域 的 。domainName 参 数 必 须 是 任 意 数 字 域 的 名 称 , 编 译 时 必 须<br />
是 确 定 的 ( 即 不 能 来 自 于 变 量 )。<br />
参 看 lowerBound/1->。<br />
异 常<br />
如 果 指 定 的 域 不 是 数 字 域 , 则 会 出 现 编 译 时 错 误 。<br />
编 译 指 令<br />
编 译 器 的 每 个 指 令 都 是 以 字 符 # 开 头 的 , 所 支 持 的 指 令 如 下 :<br />
• #include, #bininclude – 文 件 包 含 ;<br />
• #if, #then, #else, #elseif, #endif – 条 件 语 句 ;<br />
• #export, #externally – 输 出 及 引 入 类 ;<br />
• #message, #error, #requires, #orrequires – 编 译 时 间 信 息 ;<br />
• #options – 编 译 器 选 项 。<br />
源 文 件 的 包 含<br />
104
编 译 指 令 #include 用 于 将 其 它 文 件 的 内 容 在 编 译 时 包 含 进 用 户 开 发 的 程 序 代 码 中 。 其 语 法 如 下 :<br />
Pp_dir_include :<br />
#include String_literal<br />
文 字 串 (string literal) 应 该 指 向 一 个 已 有 文 件 名 。 文 件 名 可 以 包 含 路 径 名 , 但 要 记 住 : 用 于 子 目 录<br />
的 反 斜 杠 字 符 \ 是 一 个 换 码 序 列 符 , 因 此 在 要 使 用 它 的 地 方 要 写 两 次 :<br />
#include "pfc\\exception\\exception.ph"<br />
% 包 含 pfc\exception\exception.ph 文 件<br />
或 者 用 @ 字 符 在 文 件 名 前 作 前 缀 , 像 这 样 :<br />
#include @"pfc\vpi\vpimessage\vpimessage.ph"<br />
pfc\vpi\vpimessage\vpimessage.ph 文 件<br />
% 包 含<br />
从 语 义 上 来 讲 , 这 个 指 令 使 用 “ 仅 包 含 第 一 次 出 现 的 文 件 ” 策 略 , 也 就 是 说 , 如 果 一 个 编 译 单 元 中 对<br />
同 一 个 文 件 有 多 个 包 括 指 令 , 则 只 采 用 第 一 个 出 现 的 包 括 指 令 。<br />
各 包 含 文 件 必 须 含 有 分 开 的 已 经 完 成 的 范 围 。 包 含 文 件 不 能 含 有 未 完 成 的 范 围 , 也 就 是 说 , 它 含 有 的<br />
是 分 开 的 已 经 完 成 的 接 口 声 明 、 类 声 明 、 类 实 现 或 / 和 分 开 的 编 译 指 令 。<br />
编 译 器 按 下 述 方 法 来 查 找 指 定 包 括 的 源 文 件 :<br />
1. 如 果 文 件 名 中 包 括 了 绝 对 路 径 , 就 直 接 包 括 该 文 件 ;<br />
2. 否 则 , 编 译 器 就 按 命 令 行 选 项 /Include 定 义 的 路 径 搜 索 指 定 的 包 含 文 件 名 , 有 多 个 路 径 时 按 顺<br />
序 使 用 。 可 以 在 VDE 中 Project Settings 的 Directories 标 签 里 的 Include Directories 中 设<br />
置 这 些 路 径 。<br />
如 果 编 译 器 找 不 到 指 定 文 件 , 就 会 出 现 编 译 时 错 误 。<br />
二 进 制 文 件 的 包 含<br />
编 译 指 定 #bininclude 用 于 ( 将 由 string literal 串 指 定 的 ) 文 件 内 容 作 为 ::binary 类 型 的 常 数 包 含 进<br />
用 户 开 发 的 程 序 源 代 码 中 。 其 语 法 如 下 :<br />
Pp_dir_bininclude :<br />
#bininclude ( String_literal )<br />
#bininclude 编 译 指 令 告 诉 编 译 器 把 指 定 文 件 的 内 容 当 作 一 个 ::binary 常 数 的 值 插 入 。 这 个 指 令 可 以<br />
用 在 任 何 ::binary 常 数 可 以 使 用 的 地 方 。<br />
典 型 的 使 用 方 法 如 下 :<br />
constants<br />
myBin : ::binary = #bininclude ("Bin.bin"). % 由 “Bin.bin” 文 件 创 建 一 个 二 进 制 常 数 值<br />
myBin2 = #bininclude ("Bin2.bin"). % 初 始 化 一 个 二 进 制 常 数 的 简 式<br />
在 上 面 这 个 例 子 中 , 分 析 第 一 个 常 数 myBin 的 声 明 时 , 编 译 器 碰 到 了 #bininclude ("Bin.bin") 指<br />
令 。 于 是 它 在 包 含 #bininclude ("Bin.bin") 这 个 指 令 的 源 文 件 所 在 的 目 录 中 、 在 Project Settings 对<br />
话 框 的 Include Directories 表 框 中 指 定 的 目 录 中 ( 在 /Include 命 令 行 选 项 指 定 的 目 录 中 ) 查 找 是 否 有<br />
这 个 Bin.bin 文 件 。 如 果 找 到 了 , 编 译 器 就 读 这 个 文 件 , 按 该 文 件 的 内 容 形 成 正 确 的 ::binary 域 的 数 据 并<br />
将 其 作 为 myBin 常 数 的 值 。 比 如 说 ,Bin.bin 文 件 中 只 有 一 个 字 符 A,myBin 常 数 就 会 有 下 面 这 样 的 值 :<br />
105
myBin = $[0x41]<br />
% 这 里 的 0x41 是 'A' 的 十 六 进 制 ASCII 码 值<br />
string literal 应 该 指 向 一 个 已 有 文 件 名 。 这 个 指 令 的 语 法 与 前 面 “ 源 文 件 的 包 含 ” 中 的 #include 指<br />
令 是 一 样 的 , 搜 索 指 定 文 件 的 方 法 也 一 样 。<br />
输 出 和 引 入 类<br />
编 译 指 令 #export 和 #externally 分 别 用 于 确 定 要 输 出 的 类 及 要 引 入 的 类 。 其 语 法 如 下 :<br />
Pp_dir_export :<br />
#export ClassNames-comma-sep-list<br />
Pp_dir_export :<br />
#externally ClassNames-comma-sep-list<br />
这 两 个 编 译 指 令 只 能 用 于 不 构 造 对 象 的 类 classNames。 而 且 , 它 们 也 只 能 用 于 外 部 范 围 , 这 就 是 说 ,<br />
它 们 不 能 用 在 接 口 和 类 的 声 明 里 , 也 不 能 用 在 类 的 实 现 里 。<br />
缺 省 时 , 在 一 个 执 行 单 元 内 部 的 谓 词 对 其 它 执 行 单 元 来 说 是 完 全 隐 藏 的 。 而 编 译 指 令 #export 使 它 所<br />
指 定 的 那 些 类 名 对 外 部 开 放 了 , 因 而 运 行 时 这 些 类 中 声 明 的 模 块 里 的 所 有 谓 词 对 其 它 执 行 单 元 就 是 可 访 问<br />
的 。<br />
一 般 情 况 下 ,#export 编 译 指 令 用 在 目 标 模 块 是 DLL 的 工 程 中 , 它 列 出 一 个 DLL 中 所 声 明 的 类 , 这 些<br />
列 出 的 类 就 可 以 被 使 用 这 个 DLL 的 其 它 模 块 所 访 问 。<br />
如 果 某 个 编 译 单 元 输 出 一 个 类 , 该 编 译 单 元 就 应 该 含 有 这 个 类 的 实 现 。( 译 注 : 原 文 为 “If a compilation<br />
unit export some class, then this compilation unit should not contain this class implementation.”<br />
not 应 该 是 错 误 的 )<br />
#export 编 译 指 令 还 可 以 用 在 #if 编 译 指 令 中 规 定 condition 表 达 式 。 例 如 , 假 设 在 一 个 编 译 单 元 开 始<br />
的 地 方 编 译 器 碰 到 了 这 样 的 #export 编 译 指 令 :<br />
#export className<br />
而 在 后 面 编 译 器 又 遇 到 一 个 #if 编 译 指 令 , 它 以 #export 编 译 指 令 为 条 件 表 达 式 , 比 如 说 是 这 样 的 :<br />
#if #export className #then ... #endif<br />
那 么 , 编 译 器 就 会 对 #export 条 件 表 达 式 求 值 , 在 我 们 这 里 其 结 果 是 true, 接 着 就 会 执 行 条 件 编 译<br />
指 令 的 #then 分 支 。<br />
比 如 , 下 面 这 个 例 子 中 , 就 能 保 证 把 some.pack 包 包 含 到 所 编 译 的 单 元 中 :<br />
#export className<br />
...<br />
#if #export className #then #requires "some.pack" #endif<br />
而 另 一 方 面 , 如 果 没 有 前 一 个 #export 编 译 指 令 , 编 译 器 对 #export 条 件 表 达 式 的 求 值 就 会 是 false,<br />
也 就 不 会 执 行 #if 的 分 支 #then, 比 如 例 子 是 这 样 :<br />
#if #export className #then #requires "some.pack" #endif<br />
这 时 , 就 不 会 请 求 包 含 some.pack 包 。<br />
#externally 编 译 指 令 是 与 #export 编 译 指 令 配 对 的 , 它 可 以 替 代 ( 也 可 以 同 时 使 用 )IMPORTS<br />
106
指 令 用 于 定 义 文 件 中 。 这 个 指 令 列 出 一 些 类 , 它 们 是 在 一 个 模 块 中 声 明 的 但 却 是 在 其 它 模 块 中 实 现 的 。 这<br />
样 , 当 编 译 器 遇 到 这 样 的 类 时 就 不 会 发 生 错 误 。 引 述 的 类 可 以 是 在 DLL 中 实 现 ( 并 输 出 ) 的 , 运 行 时 可 以<br />
将 这 些 DLL 链 接 到 这 个 模 块 上 来 。<br />
#export 和 #externally 编 译 指 令 可 以 在 Conditional Directives 中 用 作 条 件 布 尔 表 达 式 。 例 如 :<br />
#if #export className #then #include "Some package.pack" #endif<br />
编 译 时 消 息<br />
在 编 译 工 程 模 块 时 , 可 以 用 编 译 指 令 #message、#requires、#orrequires 和 #error 来 发 布 用<br />
户 定 义 的 消 息 到 一 个 列 表 文 件 中 或 中 断 编 译 过 程 。<br />
这 些 指 令 既 可 以 用 在 范 围 ( 接 口 声 明 、 类 声 明 或 类 实 现 ) 之 外 , 也 可 以 用 在 范 围 内 但 在 段 之 外 。 其 语<br />
法 如 下 :<br />
Pp_dir_message :<br />
#message String_literal<br />
Pp_dir_error :<br />
#error String_literal<br />
Pp_dir_requires :<br />
#requires String_literal Pp_dir_orrequires-list-opt<br />
Pp_dir_orrequires :<br />
#orrequires String_literal<br />
当 编 译 器 遇 到 上 列 任 何 一 个 指 令 时 , 都 会 产 生 相 应 的 警 告 信 息 并 把 指 令 的 文 本 内 容 写 到 一 个 列 表 文 件<br />
中 去 。<br />
编 译 指 令 中 可 以 指 定 一 个 列 表 文 件 名 :<br />
/listingfile:"FileName"<br />
注 意 , 在 冒 号 前 后 都 不 要 有 空 格 。<br />
缺 省 时 , 编 译 器 不 会 为 #message、#requires 和 #orrequires 指 令 产 生 消 息 , 程 序 员 可 以 用 编 译<br />
器 选 项 打 开 这 些 消 息 :<br />
/listing:message<br />
/listing:requires<br />
/listing:ALL<br />
在 这 种 情 况 下 , 当 编 译 器 遇 到 这 些 指 令 , 比 如 :<br />
#message "Some message"<br />
就 会 把 下 面 的 文 本 写 到 列 表 文 件 中 去 :<br />
C:\Tests\test\test.pro(14,10) : information c062: #message "Some message"<br />
#requires (#orrequires) 指 令 会 把 用 户 定 义 的 关 于 需 要 源 ( 目 标 ) 文 件 的 消 息 放 到 列 表 文 件 中 去 。<br />
#orrequires 指 令 不 能 单 独 使 用 , 紧 靠 它 之 前 ( 用 空 格 或 注 释 隔 开 ) 应 有 #requires 指 令 。<br />
107
#error 指 令 总 是 终 止 编 译 并 发 布 用 户 定 义 的 错 误 消 息 到 列 表 文 件 中 , 如 :<br />
C:\Tests\test\test.pro(14,10) : error c080: #error "Compilation is interrupted"<br />
可 以 对 这 些 消 息 进 行 分 析 并 接 受 所 要 求 的 事 情 。 例 如 ,VDE 会 对 #requires 和 #orrequires 指 令 给<br />
出 的 消 息 进 行 分 析 , 自 动 地 添 加 所 有 需 要 的 PFC 包 及 标 准 库 到 被 编 译 的 工 程 ( 参 看 Handling Project<br />
Modules 主 题 )。<br />
#requires 和 #orrequires 指 令 的 例 子 :<br />
#requires @"\Common\Sources\CommonTypes.pack"<br />
#orrequires @"\Common\Lib\CommonTypes.lib"<br />
#orrequires @"\Common\Obj\Foreign.obj"<br />
#if someClass::debugLevel > 0 #then<br />
#requires @"\Sources\Debug\Tools.pack"<br />
#orrequires @"\Lib\Debug\Tools.lib"<br />
#else<br />
#requires @"\Sources\Release\Tools.pack"<br />
#orrequires @"\Lib\Release\Tools.lib"<br />
#endif<br />
#orrequires "SomeLibrary.lib"<br />
#requires "SomePackage.pack"<br />
#if someClass::debugLevel > 0 #then<br />
#orrequires @"\Debug\SomePackage.lib"<br />
#else<br />
#orrequires @"\Release\SomePackage.lib"<br />
#endif<br />
#message 指 令 的 例 子 :<br />
#message "Some text"<br />
#if someClass::someConstant > 0 #then<br />
#message "someClass::someConstant > 0"<br />
#else<br />
#message "someClass::someConstant
编 译 指 令 #options 影 响 整 个 编 译 单 元 。 这 个 指 令 只 能 用 在 外 部 范 围 及 源 文 件 的<br />
条 件 编 译 语 句 中 ( 编 译 单 元 通 过 这 个 源 文 件 传 递 给 编 译 器 ), 否 则 就 会 出 现 编 译 时 的 警 告 消 息 并 忽 略 这 个<br />
指 令 。<br />
只 能 包 含 下 面 的 编 译 选 项 :<br />
"/Warning"<br />
"/Check"<br />
"/NOCheck"<br />
"/Optimize"<br />
"/DEBug"<br />
"/GOAL"<br />
"/MAXErrors"<br />
"/MAXWarnings"<br />
对 其 它 的 输 入 编 译 器 会 产 生 非 法 选 项 的 错 误 消 息 。 如 果 有 若 干 个 #options 指 令 , 则 会 按 文 本 顺 序 处<br />
理 它 们 。<br />
条 件 编 译<br />
条 件 编 程 结 构 是 <strong>Visual</strong> <strong>Prolog</strong> 的 部 件 。 编 译 单 元 和 程 序 段 ( 包 括 空 的 ) 可 以 条 件 化 。 其 语 法 如 下 :<br />
ConditionalItem :<br />
#if Condition #then CompilationItem-list-opt ElseIfItem-list-opt<br />
ElseItem-opt #endif<br />
ElseIfItem :<br />
#elseif Condition #then CompilationItem<br />
ElseItem :<br />
#else CompilationItem<br />
这 里 的 Condition 可 以 是 任 意 表 达 式 , 它 在 编 译 时 应 能 得 到 失 败 或 成 功 的 求 值 结 果 。<br />
各 个 条 件 编 译 语 句 必 须 在 一 个 文 件 中 , 也 就 是 说 , 嵌 套 的 相 同 层 次 的 编 译 指 令 #if、#then、#elseif<br />
和 #else( 如 果 有 的 话 ) 及 #endif 必 须 在 一 个 文 件 中 。<br />
编 译 时 , 编 译 器 会 对 条 件 求 值 , 以 便 确 定 哪 些 部 分 要 包 括 在 最 终 文 件 中 。 排 除 在 最 终 程 序 外 的 那 些 部<br />
分 称 为 死 分 支 。<br />
所 有 条 件 编 译 分 支 项 都 要 进 行 语 法 检 查 , 语 法 上 必 须 正 确 。 即 便 是 对 死 分 支 , 语 法 上 也 要 正 确 。 但 编<br />
译 器 只 对 所 需 要 的 条 件 做 求 值 运 算 , 不 会 对 死 分 支 上 的 条 件 求 值 。<br />
在 条 件 句 中 出 现 的 条 件 文 本 , 不 应 该 依 赖 于 任 何 代 码 。<br />
乙 丁 译<br />
its2u@qq.com<br />
109