(+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.10000
Работает, как я полагаю. Ответ стремится к 1. Теперь я хочу выразить этот результат в виде
f =: (+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.
f 10000
Не работает.
(+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.10000
Работает, как я полагаю. Ответ стремится к 1. Теперь я хочу выразить этот результат в виде
f =: (+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.
f 10000
Не работает.
Объединение нескольких глаголов вместе с помощью сопоставления в J не создает конвейер, а создает «последовательность глаголов.", который имеет другую семантику.
То есть фраза существительного:
foo bar bar buz 10000
отличается от глаголной фразы:
f =: foo bar baz buz
f 10000
Если вам нужен конвейер глаголов, вы должны использовать некоторую форму явной композиции (т.е. обозначаемый, а не подразумеваемый).
Чаще всего конвейеры состоят из одноместных глаголов (преобразование одного входа в один выход, который становится входом для следующего глагола), поэтому мы используем @:
(или @
, но это требует большего внимания к деталям), поэтому словесный эквивалент к исходной именной фразе будет:
f =: foo @: bar @: baz @: buz
f 10000
Учитывая, что в вашем случае у нас может возникнуть соблазн наивно написать:
(+/%#) @: (0:`(>:@$:)@.(3 :'?2')"0) @: i.
Позаботившись о заключении среднего глагола (0:`(>:@$:)@.(3 :'?2')"0
) в круглые скобки, потому что мы хотим применить этот глагол и только этот глагол с нулевым рангом ("0
) и, в частности, применить среднее значение (+/ % #
) ко всем результатам, а не к каждому индивидуальный результат.
Но если мы это сделаем и запустим, мы быстро столкнемся с проблемой: бесконечная рекурсия.
В исходной именной группе глагол 0:`(>:@$:)@.(3 :'?2')"0
стоял отдельно, и поэтому $:
(анонимная рекурсия) в этом глаголе относилась к 0:`(>:@$:)@.(3 :'?2')"0
и только к 0:`(>:@$:)@.(3 :'?2')"0
.
Однако, как только мы переформулировали последовательность из трех глаголов в конвейер (f
, выше), $:
стало частью f
и, следовательно, относится к f
.
Это означает, что в этой формулировке f
, когда $:
рекурсивно относится к 1, сначала к этой 1 применяется i.
, что приводит к ,0
, затем ?
генерирует случайный бит, который с вероятностью 50% является 1, который затем $:
рекурсивно on, к которому применяется i.
....
Это хорошо известная ловушка в J. Есть два традиционных решения.
Вы можете разбить свой код на более мелкие именованные части:
f =: mean @: converge @: i.
mean =: +/ % #
converge =: 0:`(>:@$:)@.(3 :'?2')"0
который, поскольку он изолирует $:
, гарантирует, что он ссылается только на converge
.
Точно так же вы можете встроить $:
в анонимный явный контекст, существенно ограничивая его возможности:
f =: (+/%#) @: (verb def '0:`(>:@$:)@.(3 :'?2')"0 y') @: i.
Это как шоры на $:
: теперь он не может видеть за пределами verb def
. Некоторые негласные пуристы могут не согласиться с таким подходом, но в какой-то момент сам интерпретатор J применил эту тактику, когда определение со встроенным $:
было исправлено с помощью f.
.
Учитывая, что вы используете 3 : '?2'
, вы, кажется, чувствуете себя комфортно с анонимными явными контекстами. Если это так, то, возможно, стоит пойти на все и просто зафиксировать исходную, неизмененную именную фразу как явный глагол:
meanConverge =: verb define
(+/%#) 0:`(>:@$:)@.(3 :'?2')"0 i. y
)
Но если вы предпочитаете чисто молчаливое решение и хотите пойти по полной в другом направлении, мы можем исключить даже 3 : '?2'
явный код:
f =: mean @: converge @: i.
mean =: +/ % #
converge =: 0:`(>:@$:)@.(?@2:)"0
И, конечно же, есть способы переписать глагол, чтобы полностью избежать рекурсии, но это, вероятно, противоречит цели упражнения.