+1  A: 

I don't have a full answer yet, but this essay by Roger Hui has a tacit construct you can use to replace explicit while loops. Another (related) avenue would be to make the inner logic of the block into a tacit expression like so:

FUNWITHTACIT =: ] , {: + {: +. 1 + #
rowland =: monad define
    result =. >a:
    t =. 7x
    while. (# result) < y do.
      t =. FUNWITHTACIT t
      d =.  | -/ _2 {. t
      result =. ~.result,((d>1)#d)
    end.
    result
)

(You might want to keep the if block for efficiency, though, since I wrote the code in such a way that result is modified regardless of whether or not the condition was met -- if it wasn't, the modification has no effect. The if logic could even be written back into the tacit expression by using the Agenda operator.)

A complete solution would consist of finding out how to represent all the logic inside the while loop of as a single function, and then use Roger's trick to implement the while logic as a tacit expression. I'll see what I can turn up.

As an aside, I got J to build FUNWITHTACIT for me by taking the first few lines of your code, manually substituting in the functions you declared for the variable values (which I could do because they were all operating on a single argument in different ways), replaced every instance of t with y and told J to build the tacit equivalent of the resulting expression:

]FUNWITHTACIT =: 13 : 'y,({:y)+(1+#y)+.({:y)'
   ] , {: + {: +. 1 + #

Using 13 to declare the monad is how J knows to take a monad (otherwise explicitly declared with 3 : 0, or monad define as you wrote in your program) and convert the explicit expression into a tacit expression.

EDIT:

Here are the functions I wrote for avenue (2) that I mentioned in the comment:

candfun =: 3 : '(] , {: + {: +. 1 + #)^:(y) 7'
firstdiff =: [: | 2 -/\ ]
triage =: [: /:~ [: ~. 1&~: # ]
rowland2 =: triage @firstdiff @candfun

This function generates the first n-many candidate numbers using the Rowland recurrence relation, evaluates their first differences, discards all first-differences equal to 1, discards all duplicates, and sorts them in ascending order. I don't think it's completely satisfactory yet, since the argument sets the number of candidates to try instead of the number of results. But, it's still progress.

Example:

   rowland2 1000
3 5 7 11 13 23 47 101 233 467 941

Here's a version of the first function I posted, keeping the size of each argument to a minimum:

NB. rowrec takes y=(n,an) where n is the index and a(n) is the
NB. nth member of the rowland candidate sequence. The base case
NB. is rowrec 1 7. The output is (n+1,a(n+1)).
rowrec =: (1 + {.) , }. + [: +./ 1 0 + ]

rowland3 =: 3 : 0
 result =. >a:
 t =. 1 7
 while. y > #result do.
  ts =. (<"1)2 2 $ t,rowrec t
  fdiff =. |2-/\,>(}.&.>) ts
  if. 1~:fdiff do.
   result =. ~. result,fdiff
  end.
  t =. ,>}.ts
 end.
 /:~ result
) 

which finds the first y-many distinct Rowland primes and presents them in ascending order:

   rowland3 20
3 5 7 11 13 23 47 53 101 233 467 941 1889 3779 7559 15131 30323 60647 121403 242807

Most of the complexity of this function comes from my handling of boxed arrays. It's not pretty code, but it only keeps 4+#result many data elements (which grows on a log scale) in memory during computation. The original function rowland keeps (#t)+(#result) elements in memory (which grows on a linear scale). rowland2 y builds an array of y-many elements, which makes its memory profile almost the same as rowland even though it never grows beyond a specified bound. I like rowland2 for its compactness, but without a formula to predict the exact size of y needed to generate n-many distinct primes, that task will need to be done on a trial-and-error basis and thus potentially use many more cycles than rowland or rowland3 on redundant calculations. rowland3 is probably more efficient than my version of rowland, since FUNWITHTACIT recomputes #t on every loop iteration -- rowland3 just increments a counter, which is less computationally intensive.

Still, I'm not happy with rowland3's explicit control structures. It seems like there should be a way to accomplish this behavior using recursion or something.

estanford
Very interesting stuff! I'm still digesting it …
Gregory Higley
You're welcome! J is my favorite language, so any chance to explore it is a win as far as I'm concerned.There are two avenues I'm exploring at this point, one of which is quite close to your original program and the other somewhat distant. (1) do we need to keep all of `t`'s prior history? If not, it might be more efficient to only keep the last two values we generate at each step. (2) We could spool out `t` to n-many values and then triage them all at the end using `#`.
estanford
I just added a new function to my answer.
estanford
I'm going to mark your answer as accepted, even while I dissect what you've done so far. The only thing left to do is to get the `rowland2` verb to output _n_ primes rather than try _n_ candidates. I will work on that with my much more limited J skills, but I have a feeling you'll beat me to it, if you're so inclined.
Gregory Higley
Oh, and I should say that J is _among_ my favorite languages, but I'm a language junky. I have favorite languages for different tasks. For instance, I prefer J and Haskell for math and solving Project Euler problems. I like REBOL for creating DSLs. And so on.Above all, I like languages that are outside the mainstream.
Gregory Higley
I just saw on the MAA website (http://www.maa.org/mathtourist/mathtourist_8_8_08.html) that the Rowland formula generates a prime p after generating (p-3)/2 many 1's. Do you think we could use that information (or something like it) to derive an argument for `rowland2` that will say exactly how many candidates to check?(EDIT) I'm also a Project Euler user, by the way. I first found out about J by seeing brilliant solution after brilliant solution from Roger Hui in the answer forums. His code is really impressive.
estanford
Well, I don't think we can use `(p - 3) / 2`, because a subsequent quote says that Rowland "has a method for skipping over those useless 1s, but doing so essentially requires an independent test for primality."Now, I do think the optimization of keeping only the last two items in `t` is perfectly valid, because that's all we'll ever need.
Gregory Higley
By the way, I wasn't aware of the whole `13 :` thing. How useful!
Gregory Higley
Have you had a chance to look at the tutorial documentation on the jsoftware site (Primer, J for C programmers, Learning J)? They have a lot of overlapping material, but there's a lot of good insights to be had in all of them. I finished the Primer when I was first learning J (which is how I found out about `13 : 0`) and I'm going through JforC on a sporadic basis whenever I get the chance. Those docs, the labs, demos and essays on the jsoftware website are a treasure trove of cool ideas on how to get the most out of J.
estanford