J язык. Я хочу выразить результат в виде функции

(+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.10000

Работает, как я полагаю. Ответ стремится к 1. Теперь я хочу выразить этот результат в виде

f =: (+/%#)0:`(>:@$:)@.(3 :'?2')"0 i.
f 10000

Не работает.


j
person Roman    schedule 14.09.2016    source источник
comment
Что вы имеете в виду под не работает?   -  person vrs    schedule 14.09.2016
comment
выдает ошибку/неправильный результат   -  person Roman    schedule 15.09.2016


Ответы (1)


Неявная и явная композиция

Объединение нескольких глаголов вместе с помощью сопоставления в 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

И, конечно же, есть способы переписать глагол, чтобы полностью избежать рекурсии, но это, вероятно, противоречит цели упражнения.

person Dan Bron    schedule 14.09.2016
comment
ПРЕДУПРЕЖДЕНИЕ: я не тестировал этот код. - person Dan Bron; 14.09.2016
comment
Большое спасибо за столь обстоятельный ответ! Это очень полезно. - person Roman; 15.09.2016