【问题标题】:Using a prolog DCG to find & replace - code review使用 prolog DCG 查找和替换 - 代码审查
【发布时间】:2016-07-12 19:40:45
【问题描述】:

我想出了以下代码来替换所有出现在Request 中的FindReplace,并将答案放在Result 中。这是使用 DCG,所以它们都是字符代码列表。客户端代码将使用的谓词是substitute

findReplace(_, _, [], []) -->
    [].  % The end.
findReplace(Find, Replace, Result, ResultRest) -->
    Find,  % Found Find.
    { append(Replace, Intermediate, Result) },  % Put in Replace in Find's place.
    !,  % Make sure we don't backtrack & interpret Find as the next case.
    findReplace(Find, Replace, Intermediate, ResultRest).
findReplace(Find, Replace, [ C | Intermediate ], ResultRest) -->
    [ C ],  % Any other character.
    findReplace(Find, Replace, Intermediate, ResultRest).

substitute(Find, Replace, Request, Result):-
    phrase(findReplace(Find, Replace, Result, []), Request).

这适用于 SWI-Prolog。有没有人对我如何改进它有任何意见?我正在学习如何使用 DCG 和差异列表。例如,我加入了剪辑,以便在找到 Find 之后,prolog 不会回溯并将其解释为 [ C ] 案例中的普通字符。是否需要这样做,或者是否有更具声明性的方式这样做?

另一个问题 - 是否已经有一个谓词可以做与替代品相同的事情,也许是在原子上?

提前致谢。

【问题讨论】:

    标签: prolog dcg


    【解决方案1】:

    考虑使用半上下文符号来替换 DCG 中的子序列:

    eos([], []).
    
    replace(_, _) --> call(eos), !.
    replace(Find, Replace), Replace -->
            Find,
            !,
            replace(Find, Replace).
    replace(Find, Replace), [C] -->
            [C],
            replace(Find, Replace).
    
    substitute(Find, Replace, Request, Result):-
            phrase(replace(Find, Replace), Request, Result).
    

    例子:

    ?- substitute("a", "b", "atesta", R), atom_codes(A, R).
    R = [98, 116, 101, 115, 116, 98],
    A = btestb.
    

    此外,下划线比MixedCaseNamesAsYouSee 更具可读性。

    【讨论】:

    • 这很巧妙。顺便说一句,我注意到这扩展到以下内容。替换(_,_,A,B):-调用(eos,A,C),!,B = C。替换(A,D,B,F):-短语(A,B,C),!,E = C,替换(A,D,E,G),短语(D,F,G)。替换(B,C,A,E):- A=[F|D],替换(B,C,D,G),E=[F|G]。替代(A,B,C,D):-短语(替换(A,B),C,D)。 eos([], [])。这个尾递归吗?在第一次递归替换调用之后有一个 phrase 调用,在第二次之后有一个列表绑定。
    • 在示例中,短语/3 将翻译并执行“a”和“b”。该解决方案效率不高,因为翻译一遍又一遍地重做。不确定修复方法是什么。
    【解决方案2】:

    关于第二个问题,即使用原子,我写了这个实用程序,仔细阅读atomic_list_concat

    %%  replace_word(+Old, +New, +Orig, -Replaced)
    %%  is det.
    %
    %   string replacement
    %   doesn't fail if not found
    %
    replace_word(Old, New, Orig, Replaced) :-
        atomic_list_concat(Split, Old, Orig),
        atomic_list_concat(Split, New, Replaced).
    

    例子:

    ?- replace_word(a, b, atesta, X).
    X = btestb.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 2022-01-26
      • 2017-06-15
      相关资源
      最近更新 更多