Guides/Defining Verbs

From J Wiki
Jump to navigation Jump to search

Defining a Function/Verb

What in other programming languages are called Functions, are called Verbs in J.

Objectives

In this guide we will

  • show different methods of defining the same verb
  • demonstrate converting an explicit verb definition to tacit

Introduction

Let's say that we are creating an automatic password generator and need a function (verb) that generates a string of random characters. We may want to generate strings of varying length (length) and change the set of characters that are valid for use in the string (charset).

These two variables will become the arguments of our verb. Verbs are either a monad (has a single argument on its right) or a dyad (has two arguments, one on its left and one on its right). We have two arguments so we will want to create a dyadic verb. (See Guides/Multiple Verb Arguments for approaches to handle more than 2 arguments).

In J the convention is usually that the left argument (x) "controls" the behaviour of the verb and will usually alter less often than the right argument (y) which usually contains the data.

In my judgment (it often comes down to that) it is more likely that the charset will be static and the string length will change more often, so let's define x and y as follows:

  • y is: integer determining length of string to generate
  • x is: literal list of valid characters for string

There are two major forms of verb definition, Explicit and Tacit. Each has its advantages, but the both share the same basic syntax - the verb definition is assigned to a name using the primitive Copula (=: or =.).

myverbname=: myverbdefinition

Explicit definition

This form of verb definition will be more familiar to users of other languages. Explicit verbs are often simpler to read (especially for beginning J'ers) and are preferred for more complicated verbs, and verbs that require more than 2 arguments.

randStrngA=: dyad define
  lencharset=. #x           NB. calculate number of positions in charset
  idx=. ? y $ lencharset    NB. generate y random index positions for charset
  idx { x                   NB. retrieve literals at those positions from charset
)

We can use our new verb like this:

   'abcdefgh' randStrngA 6
gdgbce
   'abcdefgh0123456789' randStrngA 8
731h6gad

J's built in array handling comes to the fore now and we see that the following will generate 4 strings of length 8:

   'abcdefgh0123456789' randStrngA 4 8
57fe9dcc
3c05dcf9
76hd7a79
5gd633gb

As for any language, it is good practice to document your verbs and by using some standard conventions you can expose your verbs so utilities such as scriptdoc, export and namedoc can summarise them.

NB.*randStrngA  v  Generates a string of random literals
NB. form:  charset randStrngA len
NB. returns: length y string of random characters from set x
NB. y is: integer specifying length of string to generate
NB. x is: literal list of valid literals for string
NB. eg: 'abcdefghijk' randStrngA 8
randStrngA=: dyad define
  idx=. ? y $ #x  NB. generate y random index positions for string x
  idx { x         NB. retrieve literals at those positions from string x
)

For a simple verb like this we could also define it more succinctly using an alternative explicit form:

NB.*randStrngB  v  Generates a string of random literals
NB. form:  charset randStrngB len
NB. returns: length y string of random characters from set x
NB. y is: integer specifying length of string to generate
NB. x is: literal list of valid literals for string
NB. eg: 'abcdefghijk' randStrngB 8
randStrngB=: 4 : '(? y $ #x) { x'

The J Dictionary definition for Explicit (:) defines a couple of other explicit forms.

Tacit definition

One of J's interesting characteristics is that verbs can be described in tacit form so that the arguments are not referenced explicitly. It can take a while to get your head around tacit definition but, as with most skills, practise makes perfect. Luckily J has an inbuilt method of automatically translating a verb definition from explicit to tacit form that we can use to get us started.

We can ask J to suggest a tacit form for our explicit verb as follows:

   13 : '(? y $ #x) { x'
[ {~ [: ? ] $ [: # [           NB. suggested tacit form

So we can define a tacit version of randStrngB as follows:

randStrngC=: [ {~ [: ? ] $ [: # [

See guide on how to read/parse randStrngC

Note that this is not necessarily the optimal tacit form, and improvements can usually be made. For example some users prefer to replace the fork (a train of 3 verbs) [: # [ with the verb #@[ using the conjunction @ because they find it easier to read.

randStrngD=: [ {~ [: ? ] $ #@[

Also the construct x ?@$ y is equivalent to ? x $ y and is supported by special code. Using that knowledge we can rewrite randStrngD as follows:

randStrngE=: [ {~ ] ?@$ #@[

Again we have used the conjunction @ to form a single new verb from the verbs ? and $. We now have a train of 5 verbs -how to read/parse randStrngE.

Some users might find the verb easier to read if we replace the use of Passive (~) with parentheses:

randStrngF=: (] ?@$ #@[) { [

If we were prepared to swap the left and right arguments so that x was length of the string and y was the list of valid literals, we could get rid of some of the [ and ]verbs that just return the desired argument and write:

randStrngX=: (?@$ #) { ]

For example:

   8 randStrngX 'abcdefghij12345'
h5ij3ag3

If we're not prepared to redefine the argument definitions, we can still use a similar construct by using the adverb Passive (~) to swap the arguments before applying them to our verb:

randStrngG=: ((?@$ #) { ])~

Summary

This guide attempts to introduce the reader to methods for defining a verb in J, by working through the process using an example verb. The steps shown are just one way of approaching the subject, they included:

  • starting with a multi-line explicit definition
  • criteria for deciding on argument-order,
  • documenting the verb,
  • reduction to a single-line explicit definition,
  • conversion to a tacit defintion using 13 : ,
  • tidying by considering Passive, special code and aesthetics such as removing Capped forks.

See Also


Contributed by Ric Sherlock