## Train - simple string

For users of dfns, both novice and expert

### Train - simple string

I found myself yet again having to check if an argument is a simple string and tried my hands on a train solution. I know I understand it now because it made sense when I wrote it, but I wonder if it is as clear to others (or myself when I come back to it later). I didn’t think it would perform very well compared to other solutions, but what I found made me question if the expression is wrong or trains generally incur a penalty because of how they are applied.

`      s1←{(1=≡⍵)∧(1=≢⍴⍵)∧0=10|⎕DR ⍵}       s2←1 1 0≡≡,≢∘⍴,10|⎕DR                 x←1E3 ⍴ ⎕a      ]runtime "s1 x" "s2 x" -compare                                                                   s1 x → 5.7E¯7 |   0% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕          s2 x → 7.0E¯7 | +22% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕       x←1E6 ⍴ ⎕a      ]runtime "s1 x" "s2 x" -compare                                                                  s1 x → 5.4E¯7 |   0% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕             s2 x → 7.2E¯7 | +32% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕       x←1E3 ⍴ ⎕a 1      ]runtime "s1 x" "s2 x" -compare                                                                    s1 x → 5.5E¯7 |     0% ⎕⎕⎕                                        s2 x → 6.4E¯6 | +1076% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕       x←1E6 ⍴ ⎕a 1      ]runtime "s1 x" "s2 x" -compare                                                                       s1 x → 2.0E¯6 |       0%                                            s2 x → 5.6E¯3 | +287300% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕`
gil

Posts: 68
Joined: Mon Feb 15, 2010 12:42 am

### Re: Train - simple string

Note that the test for depth is superfluous, if (0=10|⎕DR ⍵) then ⍵ is a simple character array.

Personally, I would not use a train for something like this, I find the dfn MUCH more readable.

Morten|Dyalog

Posts: 392
Joined: Tue Sep 09, 2008 3:52 pm

### Re: Train - simple string

I would not use a train for something like this
`      {(1=≢⍴⍵)∧0=10|⎕DR ⍵}`
is perhaps clearer than this
`      1 0≡≢∘⍴,10|⎕dr`
but this?
`      (1=≢∘⍴)∧0=10|⎕DR`

Phil Last

Posts: 557
Joined: Thu Jun 18, 2009 6:29 pm

### Re: Train - simple string

Yup, I can't see any benefit, and significantly reduced ease of comprehension, for:

Code: Select all
`((1=≢∘⍴)∧0=10|⎕DR)`

vs

Code: Select all
`{(1=≢⍴⍵)∧0=10|⎕DR ⍵}`

You save 1 keystrokes and make it the job of the human reader to insert the ⍵ on reading, and understand why you need a compose...

Morten|Dyalog

Posts: 392
Joined: Tue Sep 09, 2008 3:52 pm

### Re: Train - simple string

Well ...

Ease of comprehension: It depends on what you are used to, doesn't it? Trains do require that you compose functions in a few well-defined ways, rather than by juxtaposing them. The requirement can be considered A Good Thing.

Keystrokes: Not that it matters much, but isn't it two keystrokes instead of one?
Code: Select all
`((1=≢∘⍴)∧0=10|⎕DR){(1=≢⍴⍵)∧0=10|⎕DR ⍵}`

In some contexts it's four keystrokes:
Code: Select all
`ss ← (1=≢∘⍴)∧0=10|⎕DRss ← {(1=≢⍴⍵)∧0=10|⎕DR ⍵}`
Roger|Dyalog

Posts: 215
Joined: Thu Jul 28, 2011 10:53 am

### Re: Train - simple string

Ease of comprehension: It depends on what you are used to, doesn't it?

Clearly there is an element of this. I have struggled with this for 20 years now. Recently, faced with an explosion in the amount of trains I have had to read (I read much more code than I write), I have grown a bit more accustomed to them, but a deep unease remains. I have attempted to do a bit of soul-searching to find out whether I am just an old dog. I am still working on this, trying to psychoanalyse yourself is a fundamentally dodgy business. So far, my conclusion remains that there is more to this than the stiffening of my arteries.

The train is fundamentally more complex, and provides less guarantees to the reader, than the equivalent explicit expression. If you look at this particular example, an additional operator is required to bind tally and shape together - a significant complication which I grant you that you can get used to.

I am starting to think that the deeper cause of my unease is that every train has two potentially different meanings. How do you know whether the ⎕DR at the end of our expression is intended to be used monadically or dyadically? If you already recognise the idiom, you can reason this train is probably only intended for monadic use - but when reading an unfamiliar construct, you have to keep more options open. In a train with many cars, the burden of understanding both valences can become very significant. When reading a function in which a dozen ambivalent definitions are combined as trains or glued together with compositions, I find it much harder to feel confident that I fully understand the entire body of code, or the consequences of making a change to the individual parts.

I'm sticking to my claim that the explicit expression with the ⍵ inside showing where the right argument will be referenced is a fundamentally simpler, less abstract construction. I think trains are great when they are used to express elegant mathematical constructs - often taking advantage of the above-mentioned ambivalence.

However, I am going to steer clear of them unless they are providing a VERY CLEAR advantage to something that I am trying to express. The case in question isn't even close to that. If you don't need the additional abstraction, don't use it.

Morten|Dyalog

Posts: 392
Joined: Tue Sep 09, 2008 3:52 pm

### Re: Train - simple string

I tend to agree with Morten.

Its a bit like a tomatoe being a fruit so used in a fruit salad. :-)

MikeHughes

Posts: 86
Joined: Thu Nov 26, 2009 9:03 am
Location: Market Harborough, Leicestershire, UK

### Re: Train - simple string

Minimising the keystroke count should never be a consideration when writing production code when compared to ease of readability, maintainability, and efficiency of the code. Production code is not Code Golf, or a competition.

Iv been told that 20% of the total cost of a software project is spent writing it and 80% maintaining it, (I would put it nearer 10%/90%). Writing maintainable code is very important.

So if there is no clear advantage of using function train as against other constructs such a dynamic function, I would always go to the more readable.

However, I have never written a function train, and this thread has helped me comprehend them a little. I would like to understand them better, if only to play the "Year game" or possibly code golf (where keystroke counts are important).

So can anyone recommend a primer for writing (and reading) trains?
(Something like "Train spotting for beginners" along the lines of "Quantum Physics for Dummies".)
Ray Cannon

ray

Posts: 173
Joined: Wed Feb 24, 2010 12:24 am
Location: Blackwater, Camberley. UK

### Re: Train - simple string

I might regret joining in this discussion but I guess it's already too late so here goes.

In about 1983 Dyalog APL, APL2 and NARS all introduced strand or vector notation. Respected and experienced APLers were heard to decry the imagined ambiguity and unmaintainability of this abomination.

Not many years later what remains the most unfortunate and regressive change ever made to APL was added to one then fairly quickly to many if not most of the then available APLs.

Control structures continue to be one of the two [0] easiest ways verbosely to complicate and hide the logic of a program making it almost entirely impossible to follow.

Odd really because contemporary with strand notation the advent of user defined operators had made the addition of control structures entirely redundant from the outset but nobody seemed to notice.

Then in 1997 with Dyalog 8.1 dfns arrived. The very same arguments now being levelled against trains and previously to strand notation and defined operators (by most of those who noticed them) were directed at dfns.

If a piece of code continues to work then it needs no maintenance. If it stops working or needs to be rewritten for some other reason then rewrite it. But please try to keep it as short as possible and with as few moving parts as you can because the more verbose and redundant the code you write the more chance it has of going wrong.

--------------------

[0] along with the ability to string countless functions one below the other in scripts so that it becomes impossible to juxtapose related code.

Phil Last

Posts: 557
Joined: Thu Jun 18, 2009 6:29 pm

### Re: Train - simple string

Phil Last wrote:Well, I might regret joining in this discussion but I guess it's already too late so here goes.

Actually, I completely agree with you that all of the technologies that you mention have issues if you overuse them - but then that goes for just about everything in life.

All I am really saying is that trains and dfns ALSO need to be used appropriately, they are not the best solution for every problem.

Morten|Dyalog

Posts: 392
Joined: Tue Sep 09, 2008 3:52 pm

Next