j

In j, how can I define a verb locally in one scope and pass it to a defined adverb?


I am getting an unexpected value error when I use a name to pass a verb as the argument to an adverb.

The adverb (integer binary search with predicate u and bounds x):

   bsearch=: adverb define
r=. y NB. range
while. ~:/ 1 0 + r do.
n=. ([: -: ] - 2&|) +/r NB. next
r=. n (u n)}r
end.
{.r
)

Some working code:

   >&3 bsearch 1 11
3
   works=: monad define
r=. 1,y
>&3 bsearch r
)
   works 11
3

And now for the surprising behavior:

   breaks=: monad define
p=. >&3
r=. 1,y
p bsearch r
)
   breaks 11
|value error: p
|   r=.n(    u n)}r

Setting stops and debugging shows the expected name classes at p bsearch r (verb adverb noun).

   reset=: 13!:0
   reset 1
   13!:3'breaks 2'
   breaks 11
|stop: breaks
|   p bsearch r
|breaks[2]
      4!:0 ;:'p bsearch r'
3 1 0
      5!:4<'p'
      ┌─ >
── & ─┴─ 3
      13!:21''
|stop: bsearch
|   r=.y
|bsearch[0]
      5!:4<'u'
── p

Inside breaks everything is as expected. Inside bsearch the verb u is defined in terms of a private var p that isn't there. This is completely unexpected and difficult to work with for more complex use cases.

I tried a little indirection by using ([: p ]) instead of p but the results were similar.

Using =: to set p in breaks does solve the immediate problem but is an untenable solution.

One workaround might be to have a tacit definition of bsearch so that using it doesn't introduce a new scope. I think that may be what I need here, but I want a more general solution and I want an understanding of why what I have doesn't work. What I want to be able to do is define a verb in a local scope and pass it or a verb derived from it to an explicitly defined adverb or conjunction.

Thanks


Solution

  • Use u. (and v. for a conjunction) in place of u (and v). u. is similar to u, but it uses the environment of the caller. If you define bsearch as follows:

    bsearch=: adverb define
    r=. y NB. range
    while. ~:/ 1 0 + r do.
    n=. ([: -: ] - 2&|) +/r NB. next
    r=. n (u. n)} r
    end.
    {.r
    )
    

    Then it should do what you want. See wiki.