Hel*_*lix 5 j cartesian-product
我正在尝试为J中的生命游戏功能重现APL代码.在搜索"APL中的生命游戏"之后,可以找到解释此代码的YouTube视频.目前我有一个矩阵R,它是:
0 0 0 0 0 0 0
0 0 0 1 1 0 0
0 0 1 1 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0
Run Code Online (Sandbox Code Playgroud)
我写了J代码,它生成了邻接列表(相邻方块中的活细胞数),如下所示:
+/ ((#:i.4),-(#:1+i.2),(1 _1),.(_1 1)) |. R
Run Code Online (Sandbox Code Playgroud)
并产生:
0 0 1 2 2 1 0
0 1 3 4 3 1 0
0 1 4 5 3 0 0
0 1 3 2 1 0 0
0 0 1 1 0 0 0
Run Code Online (Sandbox Code Playgroud)
我对这段代码的主要问题是它不优雅,因为((#:i.4),-(#:1+i.2),(1 _1),.(_1 1))只需要生成:
0 0
0 1
1 0
1 1
0 _1
_1 0
_1 1
1 _1
Run Code Online (Sandbox Code Playgroud)
这实际上只是矢量与其1 0 _1自身之间的外部产品或笛卡尔积.我找不到一种简单的方法来制作这种笛卡尔积,所以我的最终问题是如何更优雅地生成所需的矢量?
@Michael Berry的回答非常简洁明了.J idiom table(f"0/~)的一个纯粹例子.我喜欢它,因为它展示了J的微妙设计如何允许我们概括和扩展三年级任何人都熟悉的概念:算术表(加法表+/~ i. 10和乘法表*/~ i.12¹),即使在APL中也相对笨重.
除了那个很好的答案之外,还值得注意的是,J中有一个原语来计算笛卡尔积,即monad {.
例如:
> { 2 # <1 0 _1 NB. Or i:_1 instead of 1 0 _1
1 1
1 0
1 _1
0 1
0 0
0 _1
_1 1
_1 0
_1 _1
Run Code Online (Sandbox Code Playgroud)
请注意,monad的输入{是一个框列表,该列表中的框数决定了每个组合中的元素数.两个框的列表产生一个2元组的数组,一个3个框的列表产生一个3元组的数组,依此类推.
鉴于完整的外部产品(笛卡尔积)是如此昂贵(O(n^m)),它会发生一个问题:为什么J有这个原语?
当我们检查monad {的输出时会出现类似的误解:为什么它会被装箱?只有当我们想要合并不兼容类型和形状的数组时,才会在J中使用框.但是所有的结果{ y将具有相同的类型和形状,通过它的定义{.
那么,是什么给出的?嗯,事实证明,一旦我们理解为什么monad首先{被引入,这两个问题是相关的,并且是合理的.
我们必须记住,J中的所有动词都是矛盾的.J的语法不允许动词只是一个monad,或者只是一个dyad.当然,一个化合价或另一个化合价可能具有空的域(即没有有效的输入,如monad E.或dyad ~.或任何化合价[:),但它仍然存在.
具有空域的效价是"真实的",但其有效输入的范围是空的(对于例如有效输入的范围+是数字的想法的扩展,以及其他任何东西,如字符,产生"域错误") .
好的,好的,所以所有的动词都有两个化合价,那么呢?
好吧,在经历了APL的长期经验之后,Ken Iverson为J提供的主要设计目标之一是放弃数组索引的括号表示法(例如A[3 4;5 6;2]),并认识到从数组中选择是一个函数.
这是一个巨大的洞察力,对语言的设计和使用产生了严重影响,遗憾的是我没有足够的空间进入这里.
由于所有函数都需要一个名称,我们必须给一个选择函数.以J所有原始动词拼写与任一字形,屈折字形(在我的头时,.,:,.:等后缀附加符号),或一词尾变化的字母数字.
现在,因为选择对于面向数组的编程是如此常见和基础,所以它被赋予了一些主要的不动产(J的拼写中的区别标记),单字符字形:{².
因此,既然{被定义为选择,并且选择当然是二元的(即有两个参数:索引和数组),这就是二元组的原因{.现在我们明白为什么重要的是要注意所有动词都是矛盾的.
在设计语言时,将monad {与"选择"有一些主题关系会很好; 将动词的两个效价与主题相关联是J中的常见模式,用于优雅和助记的目的.
这种广泛的模式也是一个值得单独讨论的话题,但现在让我们关注为什么目录/笛卡尔产品被选为monad {.连接是什么?什么解释了另一个怪癖,它的结果总是装箱?
好吧,请记住,这{是为了替换 - 完全替换 - APL的旧括号下标语法和(以及许多其他编程语言和符号).这使得选择更容易,更有用,也简化了J的语法:在APL中,语法和解析器必须具有特殊的索引规则,如:
A[3 4;5 6;2]
Run Code Online (Sandbox Code Playgroud)
语法是异常的.但是男孩,从程序员的角度来看,这不是很有用和表现吗,是吧?
但那是为什么呢?多维包围符号经济的原因是什么?在这么小的空间里,我们怎么能这么说呢?
那么,让我们来看看我们在说什么.在上面的表达A[3 4;5 6;2]中,我们要求的3 次和4 次的行中,5 个和6 个列,并且在2 次平面.
也就是说,我们想要
平面2,第3行,第6列和
平面2,第4行,第5列和
想一想.我会等.
热潮,对吗?
索引是笛卡尔积.
一直都是.但肯看到了.
所以,现在,而不是说A[3 4;5 6;2]在APL(与一些挥手是否[]IO是1或0),以J说:
(3 4;5 6;2) { A
Run Code Online (Sandbox Code Playgroud)
当然,这只是简写或语法糖,用于:
idx =. { 3 4;5 6;2 NB. Monad {
idx { A NB. Dyad {
Run Code Online (Sandbox Code Playgroud)
所以我们保留了熟悉的,方便的,并且暗示分号语法(你想赌什么做链接正被拼;的也并非巧合?),而越来越转向的所有优点,{成一流的功能,因为它总是应该有been³.
这让我们回到了另一个最终的狡辩.如果他们的类型和形状都是常规的话,为什么monad {的结果是盒装的呢?这不是多余和不方便的吗?
嗯,是的,但请记住,未装箱的,即数字的LHA x { y只能从中选择项目y.
这是方便,因为它是一个经常需要选择相同的项目进行了多次(如更换'abc'与'ABC'和违约任何非ABC字符'?',我们通常会说('abc' i. y) { 'ABC','?',但是那只能是因为我们允许选择指数4,这是'?',多次).
但是,方便排除采用直板数字阵列也做多维索引.也就是说,未装箱数字选择项目的便利性(最常见的用例)也会干扰使用未装箱的数字数组来表达,例如A[17;3;8]通过17 3 8 { A.我们不能双管齐下.
因此我们需要一些其他符号来表达多维选择,并且由于二元组{具有左秩0(正是由于上述原因),并且单个原子盒可以封装任意结构,因此盒子是完美的候选者.
因此,表达A[17;3;8],而不是17 3 8 { A,我们简单地说(< 17;3;8) { A,它再次是直接的,方便的和熟悉的,并允许我们同时进行任意数量的多维选择,例如( (< 17;3;8) , (<42; 7; 2) { A),这是你想要和期望的数组面向语言.
当然,这意味着为了产生二元{期望作为输入的各种输出,monad { 必须生产盒子 ⁴.QED.
哦,和PS:因为,正如我所说,拳击允许单个原子中的任意结构,如果我们不装盒子,甚至盒子的列表会发生什么,但盒装盒子?那么,你有没有想过一种方式来说"我想要除了最后一个之外的所有指数"或第3个,第42个和第55个?好...
脚注:
¹ 需要注意的是算术表中+/~ i.10和*/~ i.12,我们的Elid可以明确的"0(存在于,"0/~ _1 0 1)因为算术动词已经是标量(显然)
² 但为什么选择特定的字形,{?
好吧,Ken故意从未公开J的拼写中使用的特定助记选择,因为他不想为他的用户指定这样的个人选择,但对我来说,Dan,{看起来像一个从右到左指向的小漏斗.也就是说,右边是一大堆数据,左边是一个小得多的流,就像龙头滴水一样.
同样地,我总是看到dyad |:像一个小咖啡桌或巨石阵trilithon侧面踢,即换位.
而单子#显然助记符(计数,理货,项目数),但对子总是提示我,因为它看起来像一个小净,保持感兴趣的项目,让一切"告吹".
但是,当然,YMMV.这正是肯从来没有为我们拼写这一点的原因.
³ 您是否也注意到在APL中,作为控制数据的索引列在数组的右侧,而在J中它们现在位于控制数据所在的左侧?
⁴ 虽然这个Jer仍然希望看到monad {产生无盒装的结果,代价是J引擎中的一些额外的复杂性,即以单个实现者为代价,并且使语言的每个用户受益
n 有很多有趣的文献更详细地介绍了这些材料,但不幸的是我现在没有时间去挖掘它.如果有足够的兴趣,我可以回来编辑答案,稍后再参考.现在,这是值得一读掌握Ĵ中,J,唐纳德·麦金太尔的名人之一J上的早期论文,这使得APL的"反常括号标记"的避开提及,也许是TL,这个博士版本回答我个人在2014年发布到J论坛.
,"0/ ~ 1 0 _1
Run Code Online (Sandbox Code Playgroud)
将为您提供所需的笛卡尔积(但您可能想将其重塑为 9 x 2)。
笛卡尔积是单一动词catalog:{
{ ;~(1 0 _1)
?????????????????
?1 1 ?1 0 ?1 _1 ?
?????????????????
?0 1 ?0 0 ?0 _1 ?
?????????????????
?_1 1?_1 0?_1 _1?
?????????????????
Run Code Online (Sandbox Code Playgroud)
Ravel(,)和unbox(>)获得9,2列表:
>,{ ;~(1 0 _1)
1 1
1 0
1 _1
0 1
0 0
0 _1
_1 1
_1 0
_1 _1
Run Code Online (Sandbox Code Playgroud)