dram.me

Logtalk脚本

补遗

  1. 关于SWI-Prolog对于命令行参数-t的处理,可以参考这里这里的讨论。—— 2017-02-24

  2. 可以使用read命令代替head的使用,例如:read -r LINE <"${NAME}.lgt"。—— 2017-02-25

虽然Logtalk对于脚本执行没有很好的支持,但只需要做适当的封装,就可以满足基本的需求。

以下是一个示例:

#!/bin/sh

ROOT="$(dirname "$(readlink -f "$0")")"

export LOGTALKHOME="$ROOT/logtalk"
export LOGTALKUSER="$ROOT/logtalk"

NAME="${1%.lgt}"

LINE="$(head -1 "${NAME}.lgt")"

case "$LINE" in
        %!*lgtunit*)
                GOAL="${LINE#%!}, logtalk_load($NAME, [hook(lgtunit)])"
                ;;
        %!*)
                GOAL="${LINE#%!}, logtalk_load($NAME)"
                ;;
        *)
                GOAL="logtalk_load($NAME)"
                ;;
esac

exec "$LOGTALKHOME"/integration/swilgt.sh -q -g "$GOAL, $NAME::run" -t halt

该示例主要实现了以下功能:

  1. 已包含环境变量的设置,对此的详细讨论可以参考安装Logtalk

  2. 支持lgtunit单元测试代码;

  3. 支持自定义初始目标(goal)。

总体来说,上面的脚本虽然有一定通用性,但在使用中,可以针对不同代码环境做适度的调整。

Logtalk中的加载器(loader)

在Logtalk中,加载器(loader)这个概念时常出现,总结来说,它包括两点主要功能(在刚接触Logtalk时可能不容易发现):

  1. 作为库的汇聚器,例如library/all_loaderlibrary/basic_types_loader

  2. 作为程序依赖库的加载器,例如examples目录中的示例程序。

第一点比较容易理解,对于第二点,需要注意的是,Logtalk有以下特点:

  1. Logtalk没有模块机制,通过对象封装;

  2. 库的实现也相对动态化,只有部分静态化分析库依赖的机制,所以在载入代码前,代码所依赖的库应该预先加载到系统中。

示例

以下通过示例说明:

:- initialization((
    logtalk_load(library(loopp)),
    logtalk_load(library(loop))
)).

:- object(foo).

    :- initialization(main).

    main :-
        loop::forto(N, 1, 20, (write(N), nl)).

:- end_object.

以上代码在运行时会提示下面的告警信息:

*     Reference to unknown object: loop
*       while compiling object foo
*       in file /home/dram/logtalk/foo.lgt between lines 10-11

通过编写独立的loader代码可以解决,示例如下:

:- initialization((
    logtalk_load(library(loopp)),
    logtalk_load(library(loop)),
    logtalk_load(foo)
)).

延展

从中可以看到,Logtalk在总体设计上较为动态化,继承了部分Lisp和Smalltalk的特性。如果有Prolog实现支持镜像化机制(image)的话,可能更为贴合Logtalk的设计。

用例驱动开发

用例驱动开发是测试驱动开发的衍生,TDD(并没有了解过TDD,这里的描述可能不准确甚至存在错误)要在编写代码前先写测试用例,也就是说在开发完成前这些用例是运行失败的。而用例驱动开发将测试用例和相关注释作为当前“设计”实例化描述,预设是成功的。而另一方面,代码和相关注释则是“实现”的描述。

这样,用例驱动开发和版本控制工具结合,可以实现将代码更改这一“点”的问题体现为时间维度的“面”的问题。一次代码更改将设计和实现的描述从一个状态推进到另一个状态,提交时的描述信息则可以体现这次更改的原因。

安装Logtalk

Logtalk的安装与常见的开源软件编译安装模式有所不同,以下列出主要的不同点:

  1. Logtalk基于Prolog环境实现,安装过程中并不需要编译,只是文件拷贝动作;

  2. Logtalk包含有用户目录的概念,增加了安装的复杂性。

生产环境

生产环境的安装,可以参考Logtalk的INSTALL.md说明。其中涉及到install.sh脚本的执行、LOGTALKHOMELOGTALKUSER环境变量的设置、logtalk_user_setup的执行等。

开发环境

开发环境的安装可以参考这篇维基的说明,总体与生产环境类似,只是省去了install.shlogtalk_user_setup的步骤。

脚本化

基于上面开发环境的思路,可以编写简单的脚本直接执行Logtalk,免去设置环境变量的过程,示例脚本如下:

#!/bin/sh

ROOT="$(dirname "$(readlink -f "$0")")"

export LOGTALKHOME="$ROOT/logtalk3"
export LOGTALKUSER="$ROOT/logtalk3"

exec "$LOGTALKHOME"/integration/swilgt.sh

四象限法则

艾森豪威尔的四象限时间和任务管理法则有广泛的应用。包括以下四个象限:

  1. Urgent & Important

  2. Urgent & Not Important

  3. Not Urgent & Important

  4. Not Urgent & Not Important

该法则在梳理出紧急且重要的任务的同时,还剔除掉了既不紧急又不重要的任务,这两点同等重要。

← older posts