Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Backus'78 style for increased productivety.

9 views
Skip to first unread message

no.to...@gmail.com

unread,
Oct 24, 2010, 6:18:01 AM10/24/10
to
The minority who understand the Backus'78 programming style
don't/won't bother to explain why it's so much more productive.

And the repeated analysis of *nix 'one-liners', is a slow and painful
way to realise that the concatenative/data-flow approach is easier
than the traditional/algol approach, to transform data.

Even Backus didn't list the psychological/cognitive basis for
the justifications of his proposals; which I'm not trained to do
either. But let's throw out some initial aims, which hopefully
others will refine/extend:
* eliminate backward and forward references [restrict the
area of concern];
* eliminate need to remember many identifiers/names;
* .... fill-in additional 'principles'.....

What's the name of the principle, that 'you should never
have to remember more that 3 concepts at once' ?

Below is a real-life-task which I've tried to morph to
a Backus'78 style implementation; via successive
refinement.

Just superficially scan-read the following pasted paragraph:
] If you want to use a dynamically linked executable, say `bash', then
] first run `ldd /bin/bash' to see what shared objects it needs.
]Then, [in addition to copying the actual binary, also] copy the listed files
]to the required positions under your intended new root directory.

So,
2] a <dynamically linked executable> has-got
2] <a list of shared objects> which all need to be copied to
2] <their respective locations>.

I've chunked <multiple-word/single-concepts> into
<angle-brackets> to help 'control' natural language and
morph it towards a scientific/program notation.

Refining the algorithm [now to the 3rd stage], using
*nix-notation (some what) looks like:
3] ldd /bin/bash |\
3] cut -f 3 -d" " |\
3] <append "cp "> |/
3] <prepend " ./"> |/
3] <run it all>

These 5 transformation-stages correspond to:
4] list 1 line for each of the <shared objects> of 'bash'
4] cut-out only that part of the line/s that we need
4] prepend "cp " to that part of the line/s
4] append " ./" to that part of the line/s
4] run the line/s, as one command per line

BTW, the data is being transformed, and the transformers
of the data are being transformed/refined/morphed from the
original natural-language task-description to executable-code.
Code transforms the data.
Analysis/design transforms the sequence-of-data-transformers.

So far this post has got a-lot-of-words.
But it just repeats a few concepts.
That's what a good/minimalist computer-language should do.
To minimise the cognitive-load, the few initial-concepts
are just morphed towards the goal.

I'm not fluent with the *nix filters [which some readers
will fill-in] which do stages 4 and 5 of <evolution "3]" above>,
but the other stages/transformations are immediately testable thus:

'ldd /bin/bash' gives you:-----
libtermcap.so.2 => /lib/libtermcap.so.2 (0x4001d000)
libdl.so.2 => /lib/libdl.so.2 (0x40021000)
libc.so.6 => /lib/i686/libc.so.6 (0x40024000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

And then 'ldd /bin/bash | cut -f 3 -d" " ' gives you:-----
/lib/libtermcap.so.2
/lib/libdl.so.2
/lib/i686/libc.so.6
/lib/ld-linux.so.2

BTW, the ability to just immediately test each stage is nice,
but can lead to a bad BASIC-hacking mentality IMO.

And stages/evolutions 3 plus 4 would give you:-----
cp /lib/libtermcap.so.2 ./
cp /lib/libdl.so.2 ./
cp /lib/i686/libc.so.6 ./
cp /lib/ld-linux.so.2 ./

AFAIK, the last stage/evolution:
"run the line/s, as one command per line";
would go from:
'ldd /bin/bash | cut -f 3 -d" " | <stage3> | <stage4> '
to
`'ldd /bin/bash | cut -f 3 -d" " | <stage3> | <stage4> '`
ie. merely enclose the one-liner in back-quotes.

IMO *nix's syntax is a baroque mess, because it was
evolved instead of designed from an integrated theory.
But if you had a modern concat-style language, where
the composition of functions is eg. designated by "|",
then the whole job could look like:-
'bash' ShowSharedObjects |
ButOnlyField3 | <-- or more generally: '3 ButOnlyField'
'cp ' Prepend2EachLine |
' ./' Append2EachLine
ExecuteIt

Instead of a one-liner, as the *nix-boys like to do,
I've spread the 5 stages-of-data-transformation over 5-lines,
for better comprehension.

The above will have inevitable errors, since I've not tested it
completely, but you must agree that:
A -> B -> C -> D -> E
is conceptually very economical;
and it's the mental effort of the programmer/user which we
want to economise on.

Just imagine how the initial-pasted-job-description above
would be transformed into Algol-format: which Backus calls
"von Neuman style" and todays-boys call "C" or "Python".

Oct. 2010. Chris Glur.


jcomeau_ictx

unread,
Oct 25, 2010, 4:31:23 AM10/25/10
to
On Oct 24, 3:18 am, no.top.p...@gmail.com wrote:
> The minority who understand the Backus'78 programming style
> don't/won't bother to explain why it's so much more productive.
> [snip]

> Just superficially scan-read  the following pasted paragraph:
> ] If you want to use a dynamically linked executable, say `bash', then
> ] first run `ldd /bin/bash' to see what shared objects it needs.
> ]Then, [in addition to copying the actual binary, also] copy the listed files
> ]to the required positions under your intended new root directory.
> [snip]

>
> Just imagine how the initial-pasted-job-description above
> would be transformed into Algol-format: which Backus calls
> "von Neuman style" and todays-boys call "C" or "Python".
>
> Oct. 2010. Chris Glur.

Hi Chris, just superficially, it looks like one of the steps to making
a chroot jail. You apparently read it a little too superficially;
you're copying the files into your 'intended new root directory' and
not 'to the *required positions under* your intended new root
directory'.

Also, 'ldd /bin/bash' on my system yields:

jcomeau@intrepid:/tmp$ ldd /bin/bash
linux-gate.so.1 => (0xb804c000)
libncurses.so.5 => /lib/libncurses.so.5 (0xb7ffe000)
libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7ffa000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7eb2000)
/lib/ld-linux.so.2 (0xb804d000)

That last line would not be seen by your script as written.

Here's how today's boys might write this in Bash, a good tool for the
job, as C is too low-level and Python is overkill:

executable=/bin/bash
chrootdir=.
for file in $executable $(ldd $executable); do
if [ -f $file ]; then # skips abbreviated filespecs and '=>'
mkdir -p $chrootdir/$(dirname $file);
cp $file $chrootdir/$(dirname $file);
fi
done

Eight lines, 3 variables, rather readable, gets the job done.

Like you and many others, I am looking for a better way. But setting
up strawmen and knocking them down won't get us there.

no.to...@gmail.com

unread,
Nov 1, 2010, 8:26:29 AM11/1/10
to
In article <a6688ea0-6805-4a20...@30g2000yqm.googlegroups.com>, jcomeau_ictx <john....@gmail.com> wrote:

> On Oct 24, 3:18=A0am, no.top.p...@gmail.com wrote:
> > The minority who understand the Backus'78 programming style
> > don't/won't bother to explain why it's so much more productive.
> > [snip]
> > Just superficially scan-read the following pasted paragraph:
> > ] If you want to use a dynamically linked executable, say `bash', then
> > ] first run `ldd /bin/bash' to see what shared objects it needs.
> > ]Then, [in addition to copying the actual binary, also] copy the listed files
> > ]to the required positions under your intended new root directory.
> > [snip]
> >
> > Just imagine how the initial-pasted-job-description above
> > would be transformed into Algol-format: which Backus calls
> > "von Neuman style" and todays-boys call "C" or "Python".
> >
> > Oct. 2010. Chris Glur.
>
> Hi Chris, just superficially, it looks like one of the steps to making
> a chroot jail.

It's just part of a 'man' that I pasted: for people who have problems with
unfamiliar abstractions, and need to start with something concrete.
And which you latched on to.

> You apparently read it a little too superficially;
> you're copying the files into your 'intended new root directory' and
> not 'to the *required positions under* your intended new root
> directory'.
>
> Also, 'ldd /bin/bash' on my system yields:
>
> jcomeau@intrepid:/tmp$ ldd /bin/bash

> linux-gate.so.1 =3D> (0xb804c000)
> libncurses.so.5 =3D> /lib/libncurses.so.5 (0xb7ffe000)
> libdl.so.2 =3D> /lib/i686/cmov/libdl.so.2 (0xb7ffa000)
> libc.so.6 =3D> /lib/i686/cmov/libc.so.6 (0xb7eb2000)


> /lib/ld-linux.so.2 (0xb804d000)
>
> That last line would not be seen by your script as written.
>

Backus'78 which has apparently gone over the top of the industriy's
heads, into the sand, took as his initial example: inner-product of
matrix; which I've never had reason to use.
There's a time to search for grammatical errors of the non-native
english posters, and there's a time to try to grasp the BIGGER subtle
concepts.

> Here's how today's boys might write this in Bash, a good tool for the
> job, as C is too low-level and Python is overkill:
>
> executable=/bin/bash
> chrootdir=.
> for file in $executable $(ldd $executable); do
> if [ -f $file ]; then # skips abbreviated filespecs and '=>'
> mkdir -p $chrootdir/$(dirname $file);
> cp $file $chrootdir/$(dirname $file);
> fi
> done
>

This is pure algol paradigm, which is all I've known for decades.


> Eight lines, 3 variables, rather readable, gets the job done.
>

When I've got 3 vars and 3 procs the coupling-combinations
count starts exploding and the cognitive load fails.

> Like you and many others, I am looking for a better way.

It's all been done already -- like the current economic crisis.


> But setting
> up strawmen and knocking them down won't get us there.

Re-read my title.
For those who have the facilities to appreciate Backus'78, it's not too
late.
BTW thanks for the code. I'll test it and might use it. Even tho'
the main concept went into the sand. BTW 'bash' is deceptively
'cognitively dense' with many unstated/hidden concepts.
Do you know the difference between 'being able to ride a
bicycle' and 'KNOWING how to ride a bicycle' ?

Learning fluency in ANOTHER language by USAGE/PRACTICE is
NOT what I nor Backus'78 advocates.

I don't find the recent 'look ma no hands', oneliner with lots of
"seds", which if *nix had been designed from theory, instead of
evolved/hacked, would have been less baroque, and in the
concatinative format of: A-> B-> C-> D.

But minimal though will convince you that the [often refered
to as] concatinative style increases productivety - considering
that maintenance & extentions are important to productivety.

Eg. I had a util to:
`show me all files in <dirTree>
younger than <Ndays>
which contain the <string>
And later extended it to:
but also contain the <String2>
and also contain the <string3>
And now that it's proven usefull, I want to extend it to:
and list the lines [grep-like] containing <string4>

So using this paradigm, after you've got/tested:
A-> B-> C,
it's easy to extend it to:
A-> B-> C-> D -> E.
Which is economical in mental effort.
Admittedly, eventually to run the CPU, it has to grovel
at the "branch to adr. N if non-zero", level. But we want
to delegate as much of they pain as possible to the machine.

jcomeau_ictx

unread,
Nov 1, 2010, 4:23:51 PM11/1/10
to
On Nov 1, 5:26 am, no.top.p...@gmail.com wrote:

> In article <a6688ea0-6805-4a20-b48a-f2bb6e51d...@30g2000yqm.googlegroups.com>, jcomeau_ictx <john.com...@gmail.com> wrote:
> > You apparently read it a little too superficially;
> > you're copying the files into your 'intended new root directory' and
> > not 'to the *required positions under* your intended new root
> > directory'.
>
> There's a time to search for grammatical errors of the non-native
> english posters, and there's a time to try to grasp the BIGGER subtle
> concepts.

I'm sorry it came across that way. I was trying to point out that you
missed one of the key points of the instructions, and so your program
would have been wrong no matter what paradigm you chose to use for the
programming. And had you accounted for that difference, your 5 lines
would have been insufficient.

> > Here's how today's boys might write this in Bash, a good tool for the
> > job, as C is too low-level and Python is overkill:
>
> > executable=/bin/bash
> > chrootdir=.
> > for file in $executable $(ldd $executable); do
> >  if [ -f $file ]; then  # skips abbreviated filespecs and '=>'
> >   mkdir -p $chrootdir/$(dirname $file);
> >   cp $file $chrootdir/$(dirname $file);
> >  fi
> > done
>
> This is pure algol paradigm, which is all I've known for decades.

>> Eight lines, 3 variables, rather readable, gets the job done.
>
> When I've got 3 vars and 3 procs the coupling-combinations
> count starts exploding and the cognitive load fails.

I'm well aware of what the paradigm is. And I don't like it. But it
does work well, up to a certain level of complexity. My tolerance for
complexity is very low, yours might be lower still. Guys that use
Microsoft development tools, from what I can see, can tolerate levels
orders of magnitude above mine.

And actually, two of my 3 variables are technically constants, placed
there for readability. The only real variable is "file".

> BTW thanks for the code. I'll test it and might use it. Even tho'
> the main concept went into the sand.

You're welcome.

> BTW 'bash' is deceptively
> 'cognitively dense' with many unstated/hidden concepts.
> Do you know the difference between 'being able to ride a
> bicycle' and 'KNOWING how to ride a bicycle' ?

Actually, I don't. It doesn't matter to me, as long as I can ride it.

> Learning fluency in ANOTHER language by USAGE/PRACTICE is
> NOT what I nor Backus'78 advocates.

I understand that, but you made a snide comment implying (to me) that
performing such a task in an Algol-evolved language would have to be
obscure, and I was attempting to prove you wrong. A knee-jerk reaction
on my part.

> But minimal though will convince you that the [often refered
> to as] concatinative style increases productivety - considering
> that maintenance & extentions are important to productivety.
>
> Eg. I had a util to:
>  `show me all files in <dirTree>
>         younger than <Ndays>
>         which contain the <string>
> And later extended it to:
>     but also contain the <String2>
>     and also contain the <string3>
> And now that it's proven usefull, I want to extend it to:
>     and list the lines [grep-like] containing <string4>
>
> So using this paradigm, after you've got/tested:
>      A-> B-> C,
> it's easy to extend it to:
>      A-> B-> C-> D -> E.
> Which is economical in mental effort.
> Admittedly, eventually to run the CPU, it has to grovel
> at the "branch to adr. N if non-zero", level. But we want
> to delegate as much of they pain as possible to the machine.

I hacked together something called "pysh" that allows that method of
development. It's really just a symlink to the Python interpreter,
with a .pythonrc.py file you can view here: http://www.jcomeau.com/blog/.pythonrc.py
that has a Forth-ish data stack. But it's not very good. I hear
ipython is better, but I haven't played with it enough to figure it
out.

w_a_x_man

unread,
Nov 1, 2010, 6:16:03 PM11/1/10
to
On Oct 24, 4:18 am, no.top.p...@gmail.com wrote:

> IMO *nix's syntax is a baroque mess, because it was
> evolved instead of designed from an integrated theory.
> But if you had a modern concat-style language, where
> the composition of functions is eg. designated by "|",
> then the whole job could look like:-
>    'bash' ShowSharedObjects |
>    ButOnlyField3 |   <-- or more generally:  '3  ButOnlyField'
>    'cp ' Prepend2EachLine  |
>    '  ./' Append2EachLine
>    ExecuteIt
>

Ruby (untested):

# Assumes no whitespace in filenames.

%x(ldd /bin/bash).split.select{|s| test(?f,s)}.map{|f|
dir = File.join( ".", File.dirname(f) )
[ "mkdir #{ dir }", "cp #{ f } #{ dir }" ] }.flatten.
each{|x| system x}

w_a_x_man

unread,
Nov 1, 2010, 7:24:03 PM11/1/10
to
On Nov 1, 6:26 am, no.top.p...@gmail.com wrote:

Ruby:

require 'date'

def age_in_days file
DateTime.time_to_day_fraction(0,0,
(Time.now - File.mtime(file)).to_i ).to_i
end

def contains? file, string
IO.read(file).index( string )
end

Dir[ "t/**/*" ].select{|f| File.file? f}.
select{|f| age_in_days(f) < 99}.
select{|f| contains?( f, "Core" )}.
select{|f| contains?( f, "Eddy" )}.
each{|f| puts IO.readlines(f).grep(/winding_loss/).
map{|s| f + ": " + s } }

=== output ===
t/t.awk: /^ *Lp/ { winding_loss = $2 }
t/t.awk: print winding_loss
t/t.awk: print winding_loss * 0.001
t/t.bak: /^ *Lp/ { winding_loss = $2 }
t/t.bak: print winding_loss
t/t.bak: print winding_loss * 0.001

no.to...@gmail.com

unread,
Nov 5, 2010, 9:24:31 PM11/5/10
to

> On Nov 1, 6:26 am, no.top.p...@gmail.com wrote:

> > In article <a6688ea0-6805-4a20-b48a-f2bb6e51d...@30g2000yqm.googlegroups.=
> com>, jcomeau_ictx <john.com...@gmail.com> wrote:
--snip--


> > But minimal though will convince you that the [often refered
> > to as] concatinative style increases productivety - considering
> > that maintenance & extentions are important to productivety.
> >
> > Eg. I had a util to:
> > `show me all files in <dirTree>
> > younger than <Ndays>
> > which contain the <string>
> > And later extended it to:
> > but also contain the <String2>
> > and also contain the <string3>
> > And now that it's proven usefull, I want to extend it to:
> > and list the lines [grep-like] containing <string4>
> >
> > So using this paradigm, after you've got/tested:
> > A-> B-> C,
> > it's easy to extend it to:
> > A-> B-> C-> D -> E.
> > Which is economical in mental effort.
>
> Ruby:
>
> require 'date'
>
> def age_in_days file
> DateTime.time_to_day_fraction(0,0,
> (Time.now - File.mtime(file)).to_i ).to_i
> end
>

Ruby looks good !


> def contains? file, string
> IO.read(file).index( string )
> end
>

> Dir[ "t/**/*" ].select{|f| File.file? f}. <-- so it's not exactly 'point free'
> select{|f| age_in_days(f) < 99}. <-- the 'data' is 'named' "f"
> select{|f| contains?( f, "Core" )}. <-- "f" is transformed,
> select{|f| contains?( f, "Eddy" )}. <-- through each stage


> each{|f| puts IO.readlines(f).grep(/winding_loss/).
> map{|s| f + ": " + s } }
>

Well definitely, this uses the style that I was meaning.

Since, eventually the CPU has to do some:
<evaluate an expression>
IFNotZeroThenJUmpTo Label,
does Ruby also have the IfTHeElse and WhileDo constructs?

Often *nix one-lines can be 4 or 5 'stages' of just data-transformers /
filters. Of course that's because the Algol-like control constructs are
embedded in the filters -- to do the heavy lifting. Eg for `tr`, `grep`,
`sed`..etc. The tricky problem seems to be, how to select this set
of 'primitives' which can do many jobs, using only this 'data
transforming' style. So 'the set of primitives' is like the 'library
of transformers/filters'.

AFAICS concatinative language theory can show minimal
sets of instructions from eg. push, pop, dup, roll, ...
which can do all instructions. Analagous to the fact that
'the 2 input NAND gate can construct any combination logic
circuit'. Or the IfThenElse & WhileDo are sufficient to do ALL
algorithms. Then instead of adding arbitrary functions to the
library, one could find a minimal/canonical set of functions
which can do any task -- in the domain.

> === output ===
> t/t.awk: /^ *Lp/ { winding_loss = $2 }
> t/t.awk: print winding_loss
> t/t.awk: print winding_loss * 0.001
> t/t.bak: /^ *Lp/ { winding_loss = $2 }
> t/t.bak: print winding_loss
> t/t.bak: print winding_loss * 0.001

> .
How do you feel towards Algol-family [C, python] languages after
you've been using Ruby for some time?

== TIA.

no.to...@gmail.com

unread,
Nov 5, 2010, 9:25:12 PM11/5/10
to

And I don't know Ruby.
But this seems indeed to be the compositional style that
Backus advocates.
Since this is not a circus for showing how clever you can juggle balls,
let's unravell the uncalled for 'look-Ma-no-hands' presentation:-
ShowSharedObjects =? %x(ldd /bin/bash)
split the text-strech into individual lines =? split
select only the <words> which represent files =? select{|s| test(?f,s)}
map{|f| dir = File


join( ".", File.dirname(f) ) [ "mkdir #{ dir }", "cp #{ f } #{ dir }" ] }

flatten
each{|x| system x}

Can we have a decoding of your code?
Can you understand that a 'look-Ma-no-hands' presentation
adds no value to the 'community'?

0 new messages