我经常遇到这个问题,但我从来不确定应该采用哪种方法。下面是处理一些季节事实的两种方法。
我想要弄清楚的是是否使用方法1或2以及每种方法的利弊,特别是对于大量的事实。
方法1似乎很浪费,因为事实是可用的,为什么要建立它们的列表(特别是一个大列表)。如果列表足够大,这肯定会有内存影响?而且它没有利用Prolog的自然回溯特性。
方法2利用回溯来为我递归,我猜它会更省内存,但通常这样做好的编程实践吗?它可能更难理解,并且可能会有其他副作用?
我能看到的一个问题是,每次调用“fail”时,我们失去了将任何东西传递回调用谓词的能力,例如,如果它是“methodtwo(SeasonResults)”,因为我们故意连续失败谓词。因此,“methodtwo”需要断言事实以存储状态。
推测方法2会更快,因为它没有(大量)列表处理要做?
我可以想象,如果我有一个列表,那么“methodone”就是正确的选择..或者总是这样吗?在任何情况下,使用“methodone”将列表断言为事实,然后使用方法2处理它们是否有意义?完全疯了吗?
但是,我也读到过,断言事实是一个非常“昂贵”的业务,所以即使对于大型列表,处理列表可能也是正确的选择?
有什么想法吗?或者有时使用一种而不是另一种,这取决于(什么)情况吗?例如,为了内存优化,使用方法2,包括断言事实,并为了速度使用方法1?
我想要弄清楚的是是否使用方法1或2以及每种方法的利弊,特别是对于大量的事实。
方法1似乎很浪费,因为事实是可用的,为什么要建立它们的列表(特别是一个大列表)。如果列表足够大,这肯定会有内存影响?而且它没有利用Prolog的自然回溯特性。
方法2利用回溯来为我递归,我猜它会更省内存,但通常这样做好的编程实践吗?它可能更难理解,并且可能会有其他副作用?
我能看到的一个问题是,每次调用“fail”时,我们失去了将任何东西传递回调用谓词的能力,例如,如果它是“methodtwo(SeasonResults)”,因为我们故意连续失败谓词。因此,“methodtwo”需要断言事实以存储状态。
推测方法2会更快,因为它没有(大量)列表处理要做?
我可以想象,如果我有一个列表,那么“methodone”就是正确的选择..或者总是这样吗?在任何情况下,使用“methodone”将列表断言为事实,然后使用方法2处理它们是否有意义?完全疯了吗?
但是,我也读到过,断言事实是一个非常“昂贵”的业务,所以即使对于大型列表,处理列表可能也是正确的选择?
有什么想法吗?或者有时使用一种而不是另一种,这取决于(什么)情况吗?例如,为了内存优化,使用方法2,包括断言事实,并为了速度使用方法1?
season(spring).
season(summer).
season(autumn).
season(winter).
% Season handling
showseason(Season) :-
atom_length(Season, LenSeason),
write('Season Length is '), write(LenSeason), nl.
% -------------------------------------------------------------
% Method 1 - Findall facts/iterate through the list and process each
%--------------------------------------------------------------
% Iterate manually through a season list
lenseason([]).
lenseason([Season|MoreSeasons]) :-
showseason(Season),
lenseason(MoreSeasons).
% Findall to build a list then iterate until all done
methodone :-
findall(Season, season(Season), AllSeasons),
lenseason(AllSeasons),
write('Done').
% -------------------------------------------------------------
% Method 2 - Use fail to force recursion
%--------------------------------------------------------------
methodtwo :-
% Get one season and show it
season(Season),
showseason(Season),
% Force prolog to backtrack to find another season
fail.
% No more seasons, we have finished
methodtwo :-
write('Done').
forall(A,B)
≡\+ \+ forall(A,B)
。 - falseforall/2
绝对比默认的失败驱动循环更好,后者无法区分成功和失败。也就是说,这个不可言状的doall(Goal) :- Goal, fail ; true.
尽管如此,它仍然在本质上极其敏感于实例化。 - false