序言(SWI) ,134个 128 127 124字节
这个答案是我和0'之间合作的一部分。我们俩共同努力,我发布的唯一原因是我赢了Rock,Paper和Scissors。
\Q-->{Q=1};"(",\N,")",\B,{findnsols(N,I,(between(2,inf,I),\+ (between(3,I,U),0=:=I mod(U-1))),L)->append(_,[Y],L),Q is Y*B}.
在线尝试!
说明
这个答案很好地说明了打高尔夫球的乐趣。
该答案使用Prologs功能强大的系统来处理定句语法。这是我们的语法略显不足。
head(1)-->[].
head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.
isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).
prime(N,Y):-
findnsols(N,I,(
between(2,inf,I),
isprime(I)
),L),
append(_,[Y],L),!.
第一条构造规则是:
head(1)-->[].
这告诉Prolog空字符串对应于1。
我们的第二个构造规则稍微复杂一点。
head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.
这告诉我们,任何非空字符串在具有这些相同规则的子句的右边,都包含一个带有这些相同规则的子句的括号。
它还告诉我们,此子句(Q
)的值遵循以下规则:
{prime(N,Y),Q is Y*B}
细分Q
为2个数字Y
和的乘积B
。 B
只是左边的子句的值,并且Y
是N
第素数,其中N
括号内的子句的值是。
该规则涵盖因子树的两个形成规则
现在为谓词定义。在非高尔夫版本中,有两个谓词在起作用(在我的实际代码中,我将这些谓词向前链接在一起)。这里的两个相关谓词是isprime/1
,它匹配一个素数,而和prime/2
,给定N
和Y
,匹配Y
是N
素数。首先我们有
isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).
这项工作非常标准地定义了素数,我们坚持认为2与之间没有数字I
,包括2但不I
存在除法I
。
下一个谓词也很简单
prime(N,Y):-
findnsols(N,I,(
between(2,inf,I),
isprime(I)
),L),
append(_,[Y],L),!.
我们findnsols
用来查找第一个N
素数,然后返回最后一个。这里的技巧是虽然findnsols
不能保证找到最小的 N
素数,但是由于SWI处理的方式,between
它总是会更快地找到较小的素数。但是,这意味着我们必须减少以防止它找到更多的素数。
高尔夫
我们可以两次在代码中转发原因。因为isprime
仅在其定义可以移入时使用一次prime
。下一步骤是prime
直接移入DCG内部,但是由于我们采用切入方式prime
来防止findnsols
产生过多的素数,因此存在一些问题。削减,削减了整个DCG,而不仅仅是我们想要的。经过一些文档挖掘,我们发现once/1
可以将其仅用于剪切这部分,而不能剪切整个DCG。但是,更多的文档挖掘表明,->
操作员也可以用来执行类似的任务。该->
运算符大致等于,,!,
因此我们将剪切移动到的另一侧append/3
并替换为->
。
在SWI-Prolog中,谓词(和规则)可以作为运算符的名称,使我们可以删除通常需要的括号。因此,我们可以通过调用规则来节省6个字节\
。