我使用早期的 ProjectEuler 问题作为了解 Factor 的一种方式。已经在第一个问题我没有找到令人满意的解决方案。
我可以用这个解决除法测试
: 3or5divisible ( n -- ? ) [ 3 mod ] [ 5 mod ] bi * 0 = ;
但我不喜欢的是
mod
的重复。当然只是两次,但是另一个问题可能需要检查200。
map
、curry
、bi
、2bi
、bi@
、数组和普通堆栈值等。我总是得到堆栈下溢或效果不匹配(使用 map
时)。我还没有找到在检查器中查看试验结果的方法。
如何将
mod
分解出来并将其应用于 { 3 5 }
或等效堆栈?mod3and5
(包括效果规范);一种将 2 1
留在堆栈上用于输入 11,另一种则返回 { 2 1 }
。
我只能想到这样做,删除其中一个模组,但最终会添加一个
bi-curry@
功能。
: 3or5divisible ( n -- ? ) 3 5 [ mod ] bi-curry@ bi * 0 = ;
一般性评论,有时重复的代码更具可读性,有时更高级别的花哨代码更好。 组合器可以发挥作用的地方是它消除了更难理解的堆栈改组。
所以,也许如果你从“最重复的”开始:
: 3or5divisible ( n -- ? )
[ 3 mod zero? ] [ 5 mod zero? ] bi or ;
看看使用命名局部变量看起来如何,不错:
:: 3or5divisible ( n -- ? )
n 3 mod zero? n 5 mod zero? or ;
然后使用花哨的组合器查看它的外观,可能更难阅读:
: 3or5divisible ( n -- ? )
3 5 [ mod zero? ] bi-curry@ bi or ;
然后看看它是如何工作的,如果你向它传递了一系列数字来检查,超级容易阅读:
: 3or5divisible ( n -- ? )
{ 3 5 } [ mod zero? ] any? ;
或者也许使用宏为任意输入生成代码:
MACRO: divisible ( ns -- quot )
[ [ '[ _ mod zero? ] ] map '[ _ cleave ] ]
[ length 1 - [ or ] <repetition> concat ] bi
append ;
然后看看它是否生成了您期望的代码:
IN: scratchpad [ { 3 5 } divisible ] expand-macros .
[ [ 3 mod zero? ] keep [ 5 mod zero? ] keep drop or ]
很多可能性...