系统地从 J 表达式中提取名词参数
Systematically extract noun arguments from J expression
从 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 : '>:?x#y'
。如果有人可以告诉我如何找到 13 :
的定义,我也许可以回答我自己的问题。
13 :
记录在 :
(显式)下的 vocabulary or NuVoc 中。
基本思路是,你想要的值x
变成[
,你想要的值y
变成]
。但是一旦最右边的token从名词(值)变成了动词,比如[
或者]
,整个语句就变成了火车,你可能需要用到动词[:
或连词 @
或 @:
以恢复您之前的组合行为。
您也可以将值替换为实际名称 x
和 y
,然后将整个内容包裹在 ((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
。
如果你的动词是这样的单行,你可以有时通过将3
或4
替换为自动将其转换为默认形式13
。
我有一些 notes on factoring verbs in j 可以帮助您进行逐步转换。
附录:用于将语句转换为默认二元组的伪代码
这仅涵盖单个语句(一行代码),如果您尝试提取的常量值被传递给连词或副词,则可能不起作用。
此外,该语句不得引用其他变量。
- 将
[ x=. xVal [ y =. yVal
附加到语句。
- 用适当的值替换
xVal
和 yVal
。
- 根据新的
x
和 y
重写原始表达式。
- 重写
statement [ x=. xVal [ y=. yVal
为:
newVerb =: (4 : 0)
statement ] y NB. we'll fill in x later.
)
(xVal) newVerb yVal
现在您有了 x
和 y
的明确定义。将它放在多行而不是使用 x (4 : 'expr') y
的原因是如果 expr
仍然包含字符串文字,您将不得不 fiddle 转义单引号。
转换第一个名词
因为你之前只有管道,所以statement
里面最右边的表达式一定是名词。使用以下规则将其转换为分叉:
y
→(])
x
→]x ([)
_
, __
, _9
... 9
→ (_:)
, (__:)
, (_9:)
.. . (9:)
n
→ n"_
(对于任何其他任意名词)
这使整体含义保持不变,因为您刚刚创建的动词会立即被调用并应用于 [ y
。
无论如何,括号中的这个新默认动词将成为您将要建造的火车的核心。从这里开始,您将使用语句中最右边的表达式,并将其移到括号内。
分叉范式
从现在开始,我们将假设我们创建的默认动词始终是叉子。
这个新的默认动词实际上不是叉子,但我们会假装它是,因为任何单标记动词都可以使用以下规则重写为叉子:
v → ([: ] v).
没有理由实际进行此转换,只是为了简化下面的规则并始终将其称为叉子。
我们不会使用钩子,因为任何钩子都可以用规则重写为叉子:
(u v) → (] u [: v ])
下面的规则应该会自动生成这种形式的火车。
转换剩余代币
现在我们可以使用以下规则转换原始管道的其余部分,一次将一个项目移动到分支中。
对于所有这些规则,(]x)?
不是 J 语法。这意味着 ]x
可能存在也可能不存在。在不更改代码含义的情况下转换 x
的用法之前,您不能将 ] x
放入。转换 x
的实例后,需要 ]x
。
遵循J约定,u
和v
表示任意动词,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
大功告成。
如果您的目标是学习隐式风格,最好从头开始学习它,而不是试图记住一个明确的算法——J4C and Learning J 是很好的资源——因为 将表达式从显式转换为默认的一般情况是棘手的.
即使忽略自J4以来没有默认连词的规定,在动词的显式定义中你可以(1)使用control words,(2)使用和修改全局变量,( 3) 将包含 x
and/or y
的表达式作为副词或连词的操作数,以及 (4) 引用自身。在一般情况下,解决 (1)、(3) 或 (4) 非常困难,而 (2) 则完全不可能。*
如果你的 J 句子是一小部分 class 表达式中的一个,有一种简单的方法可以应用分叉规则使其默认 ,这就是或多或少是 13 :
中实现的。回想一下
(F G H) y
是(F y) G (H y)
,x (F G H) y
是(x F y) G (x H y)
(Monad/Dyad叉)
([: G H) y
是G (H y)
,x ([: G H) y
是G (x H y)
(Monad/Dyad Capped Fork)
x [ y
是x
,x ] y
是y
,[ y
和] y
都是y
( Left/Right)
注意 forks 如何使用它们的中心动词作为 'outermost' 动词:Fork 给出了 g
的二元应用,而 Capped Fork 给出了一个单子的。这恰好对应于 J 中动词的两种应用模式,一元的和二元的。因此,对于 F G H
动词和 N
名词,使 "dyadic" 表达式默认的快速算法可能如下所示:
- 将
x
替换为 (x [ y)
,将 y
替换为 (x ] y)
。 (Left/Right)
- 将任何其他名词
n
替换为 (x N"_ y)
- 如果您看到模式
(x F y) G (x H y)
,请将其替换为 x (F G H) y
。 (分叉)
- 如果您看到模式
G (x H y)
,请将其替换为 x ([: G H) y
。 (*加盖叉子()
- 重复 1 到 4,直到您获得
x F y
形式,此时您获胜。
- 如果无法进行更多的简化并且您还没有获胜,那么您就输了。
可以为"monadic expressions"导出类似的算法,表达式仅依赖于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 ]) y
和 x F y
是等价的。学习规则后,修改算法得到结果[: <. [ %~ ] - |
应该不难,也就是13 : '<. (y - x | y) % x'
给出的
只要包含 x
and/or 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
* 这是一个谎言。你可以通过一些高级的巫毒魔法重构涉及这样一个动词的整个程序,cf。 Pepe Quintana's talk at the 2012 J Conference。不好看
从 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 : '>:?x#y'
。如果有人可以告诉我如何找到 13 :
的定义,我也许可以回答我自己的问题。
13 :
记录在 :
(显式)下的 vocabulary or NuVoc 中。
基本思路是,你想要的值x
变成[
,你想要的值y
变成]
。但是一旦最右边的token从名词(值)变成了动词,比如[
或者]
,整个语句就变成了火车,你可能需要用到动词[:
或连词 @
或 @:
以恢复您之前的组合行为。
您也可以将值替换为实际名称 x
和 y
,然后将整个内容包裹在 ((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
。
如果你的动词是这样的单行,你可以有时通过将3
或4
替换为自动将其转换为默认形式13
。
我有一些 notes on factoring verbs in j 可以帮助您进行逐步转换。
附录:用于将语句转换为默认二元组的伪代码
这仅涵盖单个语句(一行代码),如果您尝试提取的常量值被传递给连词或副词,则可能不起作用。
此外,该语句不得引用其他变量。
- 将
[ x=. xVal [ y =. yVal
附加到语句。 - 用适当的值替换
xVal
和yVal
。 - 根据新的
x
和y
重写原始表达式。 - 重写
statement [ x=. xVal [ y=. yVal
为:
newVerb =: (4 : 0)
statement ] y NB. we'll fill in x later.
)
(xVal) newVerb yVal
现在您有了 x
和 y
的明确定义。将它放在多行而不是使用 x (4 : 'expr') y
的原因是如果 expr
仍然包含字符串文字,您将不得不 fiddle 转义单引号。
转换第一个名词
因为你之前只有管道,所以statement
里面最右边的表达式一定是名词。使用以下规则将其转换为分叉:
y
→(])
x
→]x ([)
_
,__
,_9
...9
→(_:)
,(__:)
,(_9:)
.. .(9:)
n
→n"_
(对于任何其他任意名词)
这使整体含义保持不变,因为您刚刚创建的动词会立即被调用并应用于 [ y
。
无论如何,括号中的这个新默认动词将成为您将要建造的火车的核心。从这里开始,您将使用语句中最右边的表达式,并将其移到括号内。
分叉范式
从现在开始,我们将假设我们创建的默认动词始终是叉子。
这个新的默认动词实际上不是叉子,但我们会假装它是,因为任何单标记动词都可以使用以下规则重写为叉子:
v → ([: ] v).
没有理由实际进行此转换,只是为了简化下面的规则并始终将其称为叉子。
我们不会使用钩子,因为任何钩子都可以用规则重写为叉子:
(u v) → (] u [: v ])
下面的规则应该会自动生成这种形式的火车。
转换剩余代币
现在我们可以使用以下规则转换原始管道的其余部分,一次将一个项目移动到分支中。
对于所有这些规则,(]x)?
不是 J 语法。这意味着 ]x
可能存在也可能不存在。在不更改代码含义的情况下转换 x
的用法之前,您不能将 ] x
放入。转换 x
的实例后,需要 ]x
。
遵循J约定,u
和v
表示任意动词,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
大功告成。
如果您的目标是学习隐式风格,最好从头开始学习它,而不是试图记住一个明确的算法——J4C and Learning J 是很好的资源——因为 将表达式从显式转换为默认的一般情况是棘手的.
即使忽略自J4以来没有默认连词的规定,在动词的显式定义中你可以(1)使用control words,(2)使用和修改全局变量,( 3) 将包含 x
and/or y
的表达式作为副词或连词的操作数,以及 (4) 引用自身。在一般情况下,解决 (1)、(3) 或 (4) 非常困难,而 (2) 则完全不可能。*
如果你的 J 句子是一小部分 class 表达式中的一个,有一种简单的方法可以应用分叉规则使其默认 ,这就是或多或少是 13 :
中实现的。回想一下
(F G H) y
是(F y) G (H y)
,x (F G H) y
是(x F y) G (x H y)
(Monad/Dyad叉)([: G H) y
是G (H y)
,x ([: G H) y
是G (x H y)
(Monad/Dyad Capped Fork)x [ y
是x
,x ] y
是y
,[ y
和] y
都是y
( Left/Right)
注意 forks 如何使用它们的中心动词作为 'outermost' 动词:Fork 给出了 g
的二元应用,而 Capped Fork 给出了一个单子的。这恰好对应于 J 中动词的两种应用模式,一元的和二元的。因此,对于 F G H
动词和 N
名词,使 "dyadic" 表达式默认的快速算法可能如下所示:
- 将
x
替换为(x [ y)
,将y
替换为(x ] y)
。 (Left/Right) - 将任何其他名词
n
替换为(x N"_ y)
- 如果您看到模式
(x F y) G (x H y)
,请将其替换为x (F G H) y
。 (分叉) - 如果您看到模式
G (x H y)
,请将其替换为x ([: G H) y
。 (*加盖叉子() - 重复 1 到 4,直到您获得
x F y
形式,此时您获胜。 - 如果无法进行更多的简化并且您还没有获胜,那么您就输了。
可以为"monadic expressions"导出类似的算法,表达式仅依赖于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 ]) y
和 x F y
是等价的。学习规则后,修改算法得到结果[: <. [ %~ ] - |
应该不难,也就是13 : '<. (y - x | y) % x'
给出的
只要包含 x
and/or 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
* 这是一个谎言。你可以通过一些高级的巫毒魔法重构涉及这样一个动词的整个程序,cf。 Pepe Quintana's talk at the 2012 J Conference。不好看