Prolog项目技巧
摘要
使用Prolog脚本自动发布Prolog项目的技巧:递增版本号、提交、打标签,并通过SWI-Prolog的包系统注册新包版本。
<p><a href="https://lobste.rs/s/fbietj/prolog_projects_tips">评论</a></p>
查看缓存全文
缓存时间: 2026/05/16 07:09
# Prolog 项目技巧
来源:https://occasionallycogent.com/prolog_project_helpers/index.html
这个脚本稍微复杂一些,以至于它是用 Prolog 而不是 bash 编写的。我运行它来为库生成新版本。
第一部分非常简单:`update_pack_version/2` 解析 `pack.pl` 文件中的版本号,根据新版本是主版本、次版本还是补丁版本(通过 `increment_version/3`)递增它,然后写回新数字。`git_commit_and_tag/1` 执行指定操作,并将更改推送到 `origin`。
最后一步由 `register_new_pack/1` 实现,稍微有点神秘。它修复了一个有点烦人的问题:推送新版本后,我必须手动通过 URL 安装该新版本,以便 SWI-Prolog 服务器能够看到新版本并注册它(这样普通用户就可以直接运行 `pack_upgrade(Whatever)`)。以前我只会手动在顶级环境中执行 `pack_remove/1` 移除包,然后运行 `pack_install/2` 并显式传递要安装的包的 URL,但当然,我们可以将其自动化!
知道了我们这样做的原因,希望 `register_new_pack/1` 不再那么神秘。`download_pattern_format_string/2` 辅助谓词将 `pack.pl` 中的模式转换为格式字符串(例如将 `'https://example.com/release/*.zip'` 转换为 `"https://example.com/release/~w.zip"`),以便我们可以使用 `format/3` 下载新版本的新归档文件。不幸的是,对于仍在 GitHub 上的仓库,有一些特殊情况处理,因为出于我记不清的原因,实际下载 URL 与 pack 文件中指定的 URL 不同,这就是谓词第一个子句存在的原因。
最后,`main/1` 检查是否提供了有效的发布类型,提示确认,然后执行操作。我添加了这个提示,因为有一次我在尝试重新运行测试时不小心从历史记录中运行了该脚本,结果不得不进行太多次强制推送 😅
**清单 3:scripts/make_release.pl**
```
#!/usr/bin/env swipl
:- module(make_release, []).
:- use_module(library(readutil), [read_file_to_terms/3,
read_line_to_string/2]).
:- initialization(main, main).
increment_version(major, [Major0, _Minor, _Patch], [Major1, 0, 0]) :- !,
succ(Major0, Major1).
increment_version(minor, [Major, Minor0, _Patch], [Major, Minor1, 0]) :- !,
succ(Minor0, Minor1).
increment_version(patch, [Major, Minor, Patch0], [Major, Minor, Patch1]) :- !,
succ(Patch0, Patch1).
update_pack_version(ReleaseType, NewVersion) :-
read_file_to_terms('pack.pl', PackTerms, []),
memberchk(version(OldVersion), PackTerms),
atomic_list_concat([MajorS, MinorS, PatchS], '.', OldVersion),
maplist(atom_number, [MajorS, MinorS, PatchS], VersionNums0),
increment_version(ReleaseType, VersionNums0, VersionNums1),
atomic_list_concat(VersionNums1, '.', NewVersion),
once(select(version(OldVersion), PackTerms, version(NewVersion), NewPackTerms)),
setup_call_cleanup(open('pack.pl', write, S, []),
forall(member(T, NewPackTerms),
write_term(S, T, [fullstop(true),
nl(true),
quoted(true),
spacing(next_argument)
])),
close(S)).
git_commit_and_tag(NewVersion) :-
shell('git add pack.pl'),
shell('git commit -m "Bump version"'),
format(atom(TagCmd), "git tag v~w", [NewVersion]),
shell(TagCmd),
format(atom(PushCmd), 'git push origin master v~w', [NewVersion]),
shell(PushCmd).
download_pattern_format_string(DownloadURLPat, FormatString) :-
string_concat("https://github.com", _, DownloadURLPat), !,
string_concat(Prefix, "releases/*.zip", DownloadURLPat),
string_concat(Prefix, "archive/refs/tags/v~w.zip", FormatString).
download_pattern_format_string(DownloadURLPat, FormatString) :-
file_name_extension(Base0, Ext, DownloadURLPat),
string_concat(Base, "*", Base0),
format(string(FormatString), "~s~s.~s", [Base, "v~w", Ext]).
register_new_pack(NewVersion) :-
read_file_to_terms('pack.pl', PackTerms, []),
memberchk(name(ProjectName), PackTerms),
memberchk(download(DownloadURLPattern), PackTerms),
download_pattern_format_string(DownloadURLPattern, URLFormat),
( pack_remove(ProjectName) -> true ; true ),
format(atom(Url), URLFormat, [NewVersion]),
pack_install(ProjectName, [url(Url), interactive(false)]).
main(Args) :-
( Args = [ReleaseType], increment_version(ReleaseType, [0, 0, 0], _)
-> true
; ( format(user_error, "Usage: make_release.pl [major|minor|patch]~n", []),
halt(1) ) ),
( stream_property(user_input, tty(true))
-> format("Make new release? [y/n]: ", []),
read_line_to_string(user_input, Input),
Input == "y"
; true ),
update_pack_version(ReleaseType, NewVersion),
format("Bumping to ~w~n", [NewVersion]),
git_commit_and_tag(NewVersion),
register_new_pack(NewVersion).
```
希望这些对你使用和学习 Prolog 有所帮助!不久的将来,我会尝试将这些技巧以及我惯常使用的其他一些有用的库、工具和模板整合成一个统一的工具,帮助 Prolog 走向更多的主流开发者。在那之前,请尽情享受并明智使用!
相似文章
Prolog编程的陷阱
关于Prolog编程中常见陷阱的指南,强调使用纯声明式构造而非不纯的构造,如cut、全局状态和低级I/O。
我对Prolog的不满
Hillel Wayne的一篇博文,详细讲述了他对Prolog编程语言的不满,包括字符串问题、缺乏函数、数据类型有限以及cut操作等。
用宝可梦解释 Prolog 基础
通过宝可梦属性相克作为示例,介绍 Prolog 编程,展示逻辑编程如何优雅地建模关系数据。
标明版本!所有程序都必须报告其版本
本文主张在所有软件程序中强制进行版本标记,以改进事件响应,并以i3窗口管理器的版本报告系统作为案例研究,同时涵盖了使用Go和NixOS的实现细节。
@trq212: 我最近经常使用的一个提示:实现 <SPEC> 并在此过程中,保持一个运行中的 implementation-notes.html 文件…
一位Twitter用户分享了一个用于AI代码生成的提示:在实现规范时,保持一个运行中的实现笔记文件,记录决策、变更和权衡。