Prolog,数字列表到数字,哪个更快?

Prolog, list of digits to number, which one is faster?

所以,假设我有列表 [1,2,3,4,5],我想从这个列表中获取 12345

这是我写的代码

l_to_n(L, N) :-
    reverse(L ,P),
    list_to_n(P,0,N).
list_to_n([H|T], C, N) :-
    C1 is C + 1,
    list_to_n(T, C1, P),
    N is H*(10**C) + P.
list_to_n([], _,0).

这是我发现的东西

l_to_n(List, N) :-
    add_zero(List,Num),
    name(N,Num).

add_zero([X|Tail1],[Y|Tail2]) :-
    !,
    Y is X+48,
    add_zero(Tail1,Tail2).
add_zero([],[]) :-
    !.

哪个 faster/better 用于大列表?

这两个过程不可比:第一个计算数字,第二个计算原子。第二个显然更简单,因此可能会更有效率……如果你有一个将原子转换为整数的内置函数,当然……

第一个可以优化,而不是乘法求幂,乘以10,得到幂,然后备用10**C

在SWI-Prolog中,atomic_list_concat/2可以代替第二个...

我认为这两种方式都有点 hacky:首先你首先反转你的列表,这需要 O(n) 时间而且,更重要的是需要额外的 O(n) 内存来存储新列表。然后你执行一个没有尾递归的递归调用,同时你需要跟踪当前位置并执行指数运算。这个可以优化。

如果我对第二个的理解正确,那么您的主要目标是将数字列表转换为 ASCII 字符列表。那么你希望 name 进行有效的解析。

我提出以下谓词:

l_to_n(L,N) :-
    l_to_n(L,0,N).

l_to_n([H|T],A,N) :-
    !,
    B is A*10+H,
    l_to_n(T,B,N).
l_to_n(_,N,N).

它使用累加器A。对于列表中的每个元素,累加器乘以 10 并将 H(该数字)添加到累加器。接下来在列表的尾部进行尾递归。如果使用智能 compiler/interpreter 尾递归将阻止构建 O(n) 调用堆栈。这可能很有用,因为您需要报告结果并且撤消调用堆栈会导致额外的计算开销。

然而,这个谓词将只在一个方向上起作用:从数字到数字的列表。

演示:

?- l_to_n([1,4,2,5],N).
N = 1425.

?- l_to_n([1,2,3,4,5],N).
N = 12345.