Нахождение целых чисел, делящихся на x и y в J

Пишу свою первую программу на J для решения задачи Эйлера №1 (найти сумму всех натуральных чисел до 1000, которые являются кратно 3 или 5), я получил следующее решение:

+/(+./0=3 5|/n)#n=.i.1000

Однако я почти уверен, что есть умный способ сделать это без использования переменной. Я попытался переписать его с помощью форка, но не понимаю, как заменить выражение между () в качестве глагола, применяемого к 3 5 и i.1000. Кто-нибудь может мне помочь?


person Charles Brunet    schedule 28.02.2013    source источник
comment
Этот вопрос содержит список других способов решения PE1.   -  person Eelvex    schedule 01.03.2013


Ответы (1)


Чтобы параметризовать оба значения и, таким образом, обобщить до диадического глагола, нам нужно передать каждый из параметров туда, где они нужны. Мы можем сосредоточиться на единственной точке, где 3 5 действительно нужен, начав с этой вилки:

   3 5 ([ |/ i.@]) 1000

В общей программе нам нужен список целых чисел в двух местах. Имя (n) дало нам простой способ использовать этот список в обоих местах. Чтобы быстро поставить всю программу на место, при написании этого списка я изначально вычислил список дважды:

   3 5 ([: +/ i.@] # [:+./ 0= [ |/ i.@]) 1000

Это позволяет сформулировать всю вашу программу как двоичный глагол, но есть недостатки в том, что i. появляется дважды. Мы можем извлечь его так, чтобы он возникал только один раз, сделав его правильным зубцом вилки. В центре этой развилки находится новый внутренний глагол.

   3 5 ([: +/ [ (] # [:+./ 0= [ |/ ]) i.@]) 1000
NB.              ___________________             new "inner" verb, parenthesized

Этот внутренний глагол должен получить 3 5 в качестве аргумента, поэтому я передаю левый аргумент самого внешнего глагола в качестве левого аргумента этому внутреннему глаголу. Это означает, что Left ([) во внутреннем глаголе имеет то же значение, что и в предыдущей версии, когда оно ссылалось на самый внешний аргумент. В этом новом глаголе Right (]) имеется в виду список целых чисел, встречающихся в двух местах, где i.@] появлялось раньше.

Постскриптум: как вы показали в своем комментарии, [ |/ ] упрощается до |/

person kaleidic    schedule 28.02.2013
comment
Спасибо. Ты выучил меня в шапке. Мое решение теперь +/3 5(([:+./0=|/)#])i.1000 - person Charles Brunet; 01.03.2013
comment
Моему J очень помогло, когда я узнал, что Cap ([:) и At (@:) — это синонимы с разным синтаксисом. Cap является частью синтаксических правил вилок, а At включает в себя синтаксические правила союзов. Оба составляют два глагола. Например. [: g f и g @: f имеют одинаковое значение. - person kaleidic; 01.03.2013
comment
Другое потенциальное упрощение заключается в том, что нет необходимости фильтровать список, мы можем просто найти индексы в списке, чтобы мы могли использовать монадический I. . Если мы также используем ловушку для упрощения выбора левого или правого аргумента, мы можем написать 3 5 +/@I.@(0 = */@(|/ i.)) 1000 - person Tikkanz; 02.03.2013