0

Writing my first J program to solver Euler problem #1 (find the sum of all natural numbers below 1000 that are multiples of 3 or 5), I got the following solution:

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

However, I pretty sure there is a clever way of doing it, without using a variable. I tried to rewrite it using a fork, but I don't see how I could replace the expression between () as a verb applied to 3 5 and i.1000. Could anybody help me?

Charles Brunet
  • 21,797
  • 24
  • 83
  • 124
  • 2
    [This question](http://stackoverflow.com/questions/1557522/how-to-refactor-this-in-j) has a list of other ways of solving PE1. – Eelvex Feb 28 '13 at 23:37

1 Answers1

3

To parameterize both values, and thus generalize to a dyadic verb, we'll need to pass each of the parameters through to the places where they're needed. We can focus on the sole point where 3 5 is actually needed by starting with this fork:

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

In the overall program we need the integers list in two places. The name (n) gave us an easy way to use that list in both places. To quickly get the whole program in place, in writing this I initially calculated the list twice:

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

This succeeds at phrasing your whole program as a dyadic verb, but there are disadvantages to having i. appear twice. We can extract it to occur only once by making it the right tine of a fork. The center of that fork is a new, inner, verb.

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

This inner verb needs to receive the 3 5 as an argument so I pass through the left argument of the outermost verb as the left argument to this inner verb. This means Left ([) in the inner verb has the same value it had in the previous version, when it referred to the outermost argument. Within this new verb Right (]) refers to the list of integers, occurring in the two places that i.@] appeared before.

Postscript: As you showed in your comment, [ |/ ] simplifies to |/

kaleidic
  • 3,070
  • 1
  • 21
  • 22
  • Thank you. You learned me the cap. My solution is now `+/3 5(([:+./0=|/)#])i.1000` – Charles Brunet Mar 01 '13 at 03:44
  • 2
    It helped my J greatly when I learned that Cap (`[:`) and At (`@:`) are synonyms with different syntax. Cap is part of the syntactic rules of forks, while At involves the syntactic rules of conjunctions. Both compose two verbs. E.g. `[: g f` and `g @: f` have the same meaning. – kaleidic Mar 01 '13 at 18:25
  • The other potential simplification is that it is not necessary to filter the list, we can just find the indicies in the list so we can use monadic `I.` . If we also use a hook to simplify the selection of left or right argument we can write `3 5 +/@I.@(0 = */@(|/ i.)) 1000` – Tikkanz Mar 02 '13 at 14:50