如果你不熟悉Rowland素数序列,你可以找到它here。我在J中创建了一个丑陋的,程序性的monadic动词来生成这个序列中的第一个 n 术语,如下所示:
rowland =: monad define result =. 0 $ 0 t =. 1 $ 7 while. (# result) < y do. a =. {: t n =. 1 + # t t =. t , a + n +. a d =. | -/ _2 {. t if. d > 1 do. result =. ~. result , d end. end. result )
这非常有效,它确实在序列中生成了第一个 n 项。 (通过 n 术语,我的意思是第一个 n 不同素数。)
以下是rowland 20
的输出:
5 3 11 23 47 101 7 13 233 467 941 1889 3779 7559 15131 53 30323 60647 121403 242807
我的问题是,我怎么能用更惯用的J来写这个?我没有线索,虽然我写了以下函数来查找列表中每个连续数字之间的差异数字,这是必需步骤之一。虽然它也可能被一个比我更有经验的J程序员重构,但是:
diffs =: monad : '}: (|@-/@(2&{.) , $:@}.) ^: (1 < #) y'
答案 0 :(得分:3)
虽然我已经将estanford的答案标记为正确的答案,但自从我提出这个问题以来,我已经走了很长的路。这是在J中生成rowland prime序列的一种更惯用的方式:
~. (#~ 1&<) | 2 -/\ (, ({: + ({: +. >:@#)))^:(1000 - #) 7
表达式(, ({: + ({: +. >:@#)))^:(1000 - #) 7
生成最多1000个成员的所谓原始序列。该序列的第一个差异可以由| 2 -/\
生成,即每两个元素的差异的绝对值。 (将其与原始问题中原始的,冗长的diffs
动词进行比较。)
最后,我们删除了一些和重复的素数~. (#~ 1&<)
以获得素数序列。
这远远优于我之前的做法。它很容易变成动词,通过一点递归生成n
个素数。
答案 1 :(得分:2)
我还没有完整的答案,但是Roger Hui的this essay有一个默认的构造,你可以用它来代替显式的while循环。另一个(相关的)途径是将块的内部逻辑变成一个默认的表达式,如下所示:
FUNWITHTACIT =: ] , {: + {: +. 1 + #
rowland =: monad define
result =. >a:
t =. 7x
while. (# result) < y do.
t =. FUNWITHTACIT t
d =. | -/ _2 {. t
result =. ~.result,((d>1)#d)
end.
result
)
(您可能希望保留if块以提高效率,因为我编写代码的方式是result
被修改,无论条件是否满足 - 如果不是,修改没有效果。if
逻辑甚至可以通过使用Agenda运算符写回到默认表达式。)
完整的解决方案包括找出如何将while循环中的所有逻辑表示为单个函数,然后使用Roger的技巧将while逻辑实现为默认表达式。我会看到我能发现什么。
顺便说一句,我让J为你构建FUNWITHTACIT
,取代码的前几行,手动替换你为变量值声明的函数(我可以做,因为它们都在运行在不同方面的单个参数上),用t
替换y
的每个实例,并告诉J构建与结果表达式相等的默认值:
]FUNWITHTACIT =: 13 : 'y,({:y)+(1+#y)+.({:y)'
] , {: + {: +. 1 + #
使用13来声明monad是J知道如何获取monad(否则用你在程序中编写的3 : 0
或monad define
显式声明)并将显式表达式转换为默认表达式
编辑:
以下是我在评论中提到的为avenue(2)编写的函数:
candfun =: 3 : '(] , {: + {: +. 1 + #)^:(y) 7'
firstdiff =: [: | 2 -/\ ]
triage =: [: /:~ [: ~. 1&~: # ]
rowland2 =: triage @firstdiff @candfun
此函数使用Rowland递归关系生成前n个候选数字,计算它们的第一个差异,丢弃所有第一个差异等于1,丢弃所有重复项,并按升序对它们进行排序。我认为这还不完全令人满意,因为论证设定了候选人数而不是结果数。但是,它仍然在进步。
示例:
rowland2 1000
3 5 7 11 13 23 47 101 233 467 941
这是我发布的第一个函数的版本,将每个参数的大小保持在最小值:
NB. rowrec takes y=(n,an) where n is the index and a(n) is the
NB. nth member of the rowland candidate sequence. The base case
NB. is rowrec 1 7. The output is (n+1,a(n+1)).
rowrec =: (1 + {.) , }. + [: +./ 1 0 + ]
rowland3 =: 3 : 0
result =. >a:
t =. 1 7
while. y > #result do.
ts =. (<"1)2 2 $ t,rowrec t
fdiff =. |2-/\,>(}.&.>) ts
if. 1~:fdiff do.
result =. ~. result,fdiff
end.
t =. ,>}.ts
end.
/:~ result
)
找到第一个y-many不同的Rowland素数并按升序显示它们:
rowland3 20
3 5 7 11 13 23 47 53 101 233 467 941 1889 3779 7559 15131 30323 60647 121403 242807
此功能的大多数复杂性来自我对盒装数组的处理。它不是漂亮的代码,但在计算过程中它只会在内存中保留4+#result
个许多数据元素(以对数级增长)。原始函数rowland
将(#t)+(#result)
元素保留在内存中(以线性比例增长)。 rowland2 y
构建了一个y
的数组 - 许多元素,这使得它的内存配置文件几乎与rowland
相同,即使它永远不会超出指定的边界。我喜欢rowland2
的紧凑性,但如果没有公式来预测生成n个多个不同质数所需的y
的确切大小,则该任务需要在试错的基础上完成因此在冗余计算中可能会使用比rowland
或rowland3
更多的周期。 rowland3
可能比我的rowland
版本效率更高,因为FUNWITHTACIT
在每次循环迭代时重新计算#t
- rowland3
只增加一个计数器,计算密集型。
尽管如此,我对rowland3
明确的控制结构感到不满意。似乎应该有一种方法来使用递归或其他东西来实现这种行为。