【问题标题】:Systematically extract noun arguments from J expression从 J 表达式中系统地提取名词参数
【发布时间】:2015-03-10 07:11:40
【问题描述】:

从 J 中的表达式中提取名词作为参数的系统方法是什么?需要明确的是,包含两个文字的表达式应该成为使用左右参数而不是文字的二元表达式。

我正在尝试学习默认风格,所以如果可以避免的话,我宁愿不使用命名变量。

一个具体的例子是我做的一个简单的掷骰子模拟器:

   >:?10#6    NB. Roll ten six sided dice.
2 2 6 5 3 6 4 5 4 3
   >:?10#6
2 1 2 4 3 1 3 1 5 4

我想系统地将参数 10 和 6 提取到表达式的外部,以便它可以掷出任意数量的任意大小的骰子:

   d =. <new expression here>
   10 d 6  NB. Roll ten six sided dice.
1 6 4 6 6 1 5 2 3 4
   3 d 100  NB. Roll three one hundred sided dice.
7 27 74

请随意使用我的示例进行说明,但我希望能够遵循任意表达式的过程。

编辑:我刚刚发现使用 x 和 y 引用的版本可以使用例如自动转换为默认形式。 13 : '&gt;:?x#y'。如果有人可以告诉我如何找到13 : 的定义,我也许可以回答我自己的问题。

【问题讨论】:

  • 你的意思是d =. 4 :'&gt;:?x#y'? (或d =. [: &gt;: [: ? #
  • @Eelvex 请后者。引用定义的推导已经很清楚了,但我想看看人们如何从内联常量到一般的有上限的分叉版本。
  • 第一步:根据词汇使用原语。第 2 步:使用forks and hooks 创建更复杂的动词。第 3 步:使用@&amp; 处理更复杂的动词。
  • 您是否正在寻找一组可以遵循的规则,以便将任何显式定义转换为默认定义?如果13 : 不能每次都这样做,我很确定转换有一些艺术。
  • @Dane 这就是我一直在寻找的东西,但我可能有点天真。看起来它通常是无法实现的,但有多种有用的程序适用于许多情况。 tangentstorm 和 algorithmshark 为这些案例提供了充足的帮助。 :)

标签: refactoring j tacit-programming


【解决方案1】:

如果你的目标是学习隐性风格,最好从头开始学习,而不是试图记住一个明确的算法——J4CLearning J 是很好的资源——因为一般情况将表达式从显式转换为默认表达式是棘手的

即使忽略自 J4 以来一直没有关于默认连词的规定,在动词的显式定义中,您可以 (1) 使用 control words,(2) 使用和修改全局变量,(3) 放置表达式包含 x 和/或 y 作为副词或连词的操作数,以及 (4) 引用自身。在一般情况下,求解 (1)、(3) 或 (4) 非常困难,而 (2) 则完全不可能。*

如果你的J语句是一小类表达式之一,有一个简单的方法可以应用fork规则使其默认,这或多或少是在@中实现的987654329@。回想一下

  • (F G H) y(F y) G (H y)x (F G H) y(x F y) G (x H y)Monad/Dyad Fork
  • ([: G H) yG (H y)x ([: G H) yG (x H y)Monad/Dyad Capped Fork
  • x [ yxx ] yy[ y] y 都是 y左/右

注意分叉如何使用它们的中心动词作为“最外层”动词:Fork 给出了 g 的二元应用,而 Capped Fork 给出了单子应用。这正好对应于动词在 J 中的两种应用模式,一元和二元。因此,对于F G H 动词和N 名词,用于使默认为“二元”表达式的快速而简单的算法可能如下所示:

  1. x 替换为(x [ y),将y 替换为(x ] y)。 (左/右
  2. 将任何其他名词n 替换为(x N"_ y)
  3. 如果您看到(x F y) G (x H y) 模式,请将其替换为x (F G H) y。 (分叉
  4. 如果您看到G (x H y) 模式,请将其替换为x ([: G H) y。 (*Capped Fork()
  5. 重复 1 到 4,直到获得 x F y 表格,此时您获胜。
  6. 如果无法进行更多简化并且您还没有获胜,那么您就输了。

可以为“一元表达式”派生类似的算法,表达式仅依赖于y。这是一个示例推导。

<. (y - x | y) % x                          NB. start
<. ((x ] y) - (x [ y) | (x ] y)) % (x [ y)  NB. 1
<. ((x ] y) - (x ([ | ]) y)) % (x [ y)      NB. 3
<. (x (] - ([ | ])) y) % (x [ y)            NB. 3
<. x ((] - ([ | ])) % [) y                  NB. 3
x ([: <. ((] - ([ | ])) % [)) y             NB. 4 and we win

这忽略了一些明显的简化,但达到了目标。您可以混合各种其他规则来简化,例如长火车规则——如果Train 是奇数长度的火车,那么(F G (Train)) 等价于(F G Train)——或者观察到x ([ F ]) yx F y 是等价的。学习了规则之后,修改算法应该不难得到[: &lt;. [ %~ ] - |的结果,也就是13 : '&lt;. (y - x | y) % x'给出的结果。

只要包含x 和/或y 的表达式是副词或连词的操作数,就会达到失败条件。有时可以通过一些深度重构以及^:} 的动词和动名词形式的知识来恢复默认形式,但我怀疑这是否可以通过编程方式完成。

这就是使 (1)、(3) 和 (4) 变得困难而不是不可能的原因。知道$: 是如何工作的,一个默认的程序员可以很容易地为Ackermann function 找到一种默认的形式,而聪明的程序员甚至可以重构它以提高效率。如果你能找到这样的算法,你就会避开程序员,句号。

   ack1 =: (1 + ])`(([ - 1:) $: 1:)`(([ - 1:) $: [ $: ] - 1:)@.(, i. 0:)
   ack2 =: $: ^: (<:@[`]`1:) ^: (0 < [) >:
   3 (ack1, ack2) 3
61 61
   TimeSpace =: 6!:2, 7!:2@]  NB. iterations TimeSpace code
   10 TimeSpace '3 ack1 8'
2.01708 853504
   10 TimeSpace '3 ack2 8'
0.937484 10368

* 这是一种谎言。您可以通过一些高级巫术魔术重构涉及这样一个动词的整个程序,参见。 Pepe Quintana's talk2012 J Conference。不漂亮。

【讨论】:

  • 默示动词也可以引用自己还是我误解$:
  • @FUZxxl 他们可以,这就是为什么情况(4)并非不可能,但将任意递归重构为默认形式并非易事。例如,记忆(尤其是当你需要比M. 更强大的东西时)是一场噩梦。
  • 哦,是的。我讨厌M. 在选择记忆时是如何超级不可预测的。我感觉它测量执行时间并在超过某个阈值时记住它,但我可能错了。
【解决方案2】:

13 : 记录在vocabularyNuVoc:(显式)中。

基本思想是你想成为x的值变成[,你想成为y的值变成]。但是一旦最右边的记号从名词(值)变成像[]这样的动词,整个语句就变成了火车,你可能需要使用动词[:或连词@987654335 @ 或@: 来恢复你之前的构图行为。

您还可以将值替换为实际名称xy,然后将整个内容包含在 ((dyad : ' ... ')) 中。那就是:

>:?10#6    NB. Roll ten six sided dice.

可以变成:

10 (dyad : '>: ? x # y') 6  NB. dyad is predefined. It's just 4.

如果你只需要y参数,你可以使用monad,它被预定义为3。名称verb 也是3。当我提供一元和二元版本时,我倾向于使用verb :,而当我只需要一元含义时,我倾向于使用monad

如果您的动词是这样的单行动词,您可以有时通过将34 替换为13 来自动将其转换为默认形式。

我有一些notes on factoring verbs in j 可以帮助您逐步进行转换。

附录:将语句转换为默认 dyad 的伪代码

这仅涵盖单个语句(一行代码),如果您尝试提取的常量值被传递给连词或副词,则可能无法正常工作。

此外,该语句不得引用其他变量。

  • [ x=. xVal [ y =. yVal 附加到语句中。
  • 用适当的值替换xValyVal
  • 用新的xy 重写原始表达式。
  • statement [ x=. xVal [ y=. yVal改写为:

newVerb =: (4 : 0)
  statement ] y   NB. we'll fill in x later.
)
(xVal) newVerb yVal

现在您有了一个关于xy 的明确定义。将它放在多行而不是使用 x (4 : 'expr') y 的原因是,如果 expr 仍然包含字符串文字,您将不得不摆弄转义单引号。

第一个名词的转换

由于您之前只有管道,所以statement 中最右边的表达式必须是名词。使用以下规则将其转换为分叉:

  • y(])
  • x]x ([)
  • _, __, _9 ... 9(_:), (__:), (_9:) ... (9:)
  • nn"_(对于任何其他任意名词)

这使整体含义保持不变,因为您刚刚创建的动词会立即被调用并应用于[ y

无论如何,括号中的这个新的默认动词将成为您将构建的火车的核心。从现在开始,您可以使用语句中最右边的表达式,并将其移动到括号内。

分叉范式

从现在开始,我们将假设我们正在创建的默认动词始终是一个叉子。

这个新的默认动词实际上不是叉子,但我们会假装它是,因为任何单词元动词都可以使用规则重写为叉子:

v → ([: ] v).

没有理由实际进行这种转换,只是为了简化下面的规则并始终将其称为分叉。

我们不会使用钩子,因为任何钩子都可以用规则重写为叉子:

(u v) → (] u [: v ])

下面的规则应该自动生成这种形式的火车。

转换剩余的令牌

现在我们可以使用以下规则来转换原始管道的其余部分,一次将一项移动到分叉中。

对于所有这些规则,(]x)? 不是 J 语法。这意味着]x 可能存在也可能不存在。在不更改代码含义的情况下转换x 的用法之前,您不能放入] x。转换x 的实例后,]x 是必需的。

按照 J 约定,uv 代表任意动词,n 是任意名词。请注意,这些包括动词

tokens y u (]x)? (fork) ] y  →  tokens   (]x)? (]  u fork) ] y
tokens x u (]x)? (fork) ] y  →  tokens    ]x   ([  u fork) ] y
tokens n u (]x)? (fork) ] y  →  tokens   (]x)? (n  u fork) ] y
tokens u v (]x)? (fork) ] y  →  tokens u (]x)? ([: v fork) ] y

副词或连词没有规则,因为你应该把它们当作动词的一部分。例如+:^:3 应该被视为单个动词。同样,括号中的任何内容都应单独保留为一个短语。

无论如何,请继续应用这些规则,直到您用完令牌。

清理

你应该得到:

newVerb =: (4 : 0)
  ] x (fork) ] y
)
(xVal) newVerb yVal

这可以改写为:

(xVal) (fork) yVal

你就完成了。

【讨论】:

  • 有用的一般说明,但我仍然缺少一般程序。也许没有,因为13 : 不保证提供默认形式。您是否知道我如何查看 13 : 使用的代码/算法(而不是其文档)?
  • J的实现在Hui的“An Implementation of J”中有描述。这里有一个可读的 html 版本:sblom.github.io/openj-core/ioj.htm ... 附录 D 将原语映射到包含其实现的文件名。 cx.c 的底部似乎是 : 的左参数映射到函数的位置,稍微挖掘一下表明实现是 jtvtrans 这里:github.com/openj/core/blob/… ...我恐怕理解那是什么代码确实需要大量研究。
  • 我扩展了我的答案,在伪代码中包含了一个(希望是)完整的算法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多