如何在Scheme和Prolog中获取列表的第一个,中间和最后一个元素?

3
我将尝试在Scheme和Prolog中编写一个函数,以返回列表的第一个、中间和最后一项。例如:find([4,5,8,7,9],L), L = [4,8,9]
我已经为Scheme语言想出了以下代码,但是我对Prolog很陌生,不知道如何在Prolog中获得相同的结果。
(define (frst L)
   (car L))

(define (last L)
   (if (null? (cdr L))
       (car L)
       (last (cdr L))))

(define (nth L x)
   (if (= x 1)
       (car L)
       (nth (cdr L) (- x 1))))

(define (firstMidLast L)
   (list (frst L)
         (nth L (ceiling (/ (length L) 2)))
         (last L)))

1
根据“帖子中应删除问候语,感谢语,标签行和称谓吗?”的规定,本文已进行了编辑。 - MatteoSp
1
具有偶数项的列表会得到什么? - gusbro
2个回答

4

这里有另一种方法!

  • “诀窍”是以两种不同的速度“向下遍历”同一个列表。
  • 第一个参数索引使得目标 list_first_mid_last(+,?,?,?) 保持确定性。

我们像这样定义 list_first_mid_last/4

list_first_mid_last([E|Es],E,M,L) :-
    ahead_of_mid_last([E|Es],[E|Es],M,L).

ahead_of_mid_last([],[M|_],M,M).
ahead_of_mid_last([F|Fs],Es,M,L) :-
   more_ahead_of_mid_last(Fs,F,Es,M,L).

more_ahead_of_mid_last([],L,[E|_],E,L).
more_ahead_of_mid_last([F|Fs],_,Es,E,L) :-
   evenmore_ahead_of_mid_last(Fs,F,Es,E,L).

evenmore_ahead_of_mid_last([],L,[E|_],E,L).
evenmore_ahead_of_mid_last([F|Fs],_,[_|Es],M,L) :-
    more_ahead_of_mid_last(Fs,F,Es,M,L).

让我们运行几个查询,将Prolog1和Scheme2的结果并排放置!

% Prolog                                     % ; Scheme
?- list_first_mid_last([1],F,M,L).            % > (firstMidLast `(1))
F = M, M = L, L = 1.                          % (1 1 1)
?- list_first_mid_last([1,2],F,M,L). % > (firstMidLast `(1 2)) F = M, M = 1, L = 2. % (1 1 2)
?- list_first_mid_last([1,2,3],F,M,L). % > (firstMidLast `(1 2 3)) F = 1, M = 2, L = 3. % (1 2 3)
?- list_first_mid_last([1,2,3,4],F,M,L). % > (firstMidLast `(1 2 3 4)) F = 1, M = 2, L = 4. % (1 2 4)
?- list_first_mid_last([1,2,3,4,5],F,M,L). % > (firstMidLast `(1 2 3 4 5)) F = 1, M = 3, L = 5. % (1 3 5)
?- list_first_mid_last([1,2,3,4,5,6],F,M,L). % > (firstMidLast `(1 2 3 4 5 6)) F = 1, M = 3, L = 6. % (1 3 6)
?- list_first_mid_last([1,2,3,4,5,6,7],F,M,L).% > (firstMidLast `(1 2 3 4 5 6 7)) F = 1, M = 4, L = 7. % (1 4 7)

注脚1: 使用版本7.3.11(64位)。
注脚2: 使用解释器SCM版本5e5(64位)。


1
这个能不能更加确定一点呢?或者我们应该对索引期望更多? - false
2
@false。哇啊!嗯...,voilà! - repeat

1
假设列表中有偶数项,你可以选择其中一项(在这种情况下是第一个),则该过程应该有效:
find([First|List], [First, Middle, Last]):-
  append(_, [Last], [First|List]),
  length(List, Length),
  NLength is Length >> 1,
  nth0(NLength, [First|List], Middle).

这个从句的头实例化了列表的第一个项目,然后append/3获取最后一个项目,length/2计算列表的大小-1,>>/2将该大小除以2,nth0/3将获取中间项。


1
@repeat: 我改进了答案,使其返回与您告诉我Scheme对长度为1和2的输入列表执行的相同项目。 - gusbro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接