Calling J from Python

Alexander Schmolck a.schmolck at gmail.com
Fri Feb 9 11:28:55 EST 2007


[restoring context]
"Ant" <antroy at gmail.com> writes:
> > On Feb 6, 12:21 am, greg <g... at cosc.canterbury.ac.nz> wrote:
> >
> > Alexander Schmolck wrote:
> > > For example I once wrote this (slow) code to display
> > > part of a mandelbrot fractal:
> > >     load'viewmat'
> > >     viewmat+/2&>:|((j.~/~(%~i:)99)&+@:*:)^:(i.32)0
> > > It'll likely require you more typing in python,
> >
> > Yes, but with Python you wouldn't have to spend a
> > couple of weeks sitting and thinking before starting
> > to type that line...

(it's actually reasonably straightforward, if someone really cares I might
post a translation)

> 
> This is a good point often overlooked. 

There is of course some truth in Greg's statement -- J code will likely have a
higher thought/character ratio (even after adjusting for differences in
average token-length) -- but I don't think that is in itself terribly
interesting.

What is in my opinion of interest is how much of the additional thought you
need to put in in order to achieve higher terseness is spent

a) on more pentrating insight on the problem as such, encouraged by the
   mind-set and abstractions associated with a language (let's call this
   expressiveness)

and how much of it is spent

b) on perl-golf style geek masturbation that focuses on recalling and
   exploiting the language's various behavioral oddities that are only of
   coincidental or low-level relevance to the problem (let's call this
   golf-syndrome)

I'm not claiming that the boundaries between the two are always unambigious,
but I think the distinction is pretty important when discussing pros and cons
of differences in terseness between languages.

Apart from scaling better, one reason that a), expressiveness, is much more
interesting than b), golf-syndrome, is that it translates to some extent even
to writing code in other languages as it enriches the programmer's reservoir
of metaphors and abstractions. Typically this also has a beneficial effect
for coding even in languages that offer no direct support for these
abstractions (I bet a programmer with, say extensive python, J and prolog
experience and just a little bit of C background is in many cases likely to
come up with a superior C solutions to challenging problems than someone who's
got the same amount of experience in C only).

Therefore...

> You often get these threads on c.l.python about "How can I do this in one
> line", usually with some example of how it is done in only 13 characters in
> Perl. Yes you may spend less time typing - but unless you are a true expert
> in (J, Perl, other terse language) the time you spend actually working out
> how to type it, and in debugging it far outweighs the time you'd spend on
> all of that typing in a clean but more verbose language such as Python.

... I also don't think your pairing of J and Perl is particularly helpful. As
long as no one can point me to some resonable examples demonstrating otherwise
I flattly deny that Perl is more concise than python in an *interesting* way,
i.e. by encouraging or enabling a)

(BTW "not interesting" != "not practically relevant"; harking back to my
previous posts, typing effort *does matter* in some contexts, such as
command-line one-liners; IMO the only thing perl is useful for.)

J, on the other hand, whilst also suffering somewhat from golf-syndrome, does
in my opinion also enable a)-style terseness. Let me give an example:

Before reading further, how would you code a program that gives the following
output ('skewed' sierpinski-triangle) in python? I'll give some remarkably
concise and IMO lucid J code and a python translation below.


*               
**              
* *             
****            
*   *           
**  **          
* * * *         
********        
*       *       
**      **      
* *     * *     
****    ****    
*   *   *   *   
**  **  **  **  
* * * * * * * * 
****************








SPOILERS AHEAD

































J solution
----------

I can think of two nice ways in J, 13 and 16 characters long respectively and
each expressing something essential and non-trival about the problem in a way
that would be more cumbersome in python.

Here's the first one:

(,,.~)^:4,'*'                  NB. due to Cliff Reiter, slightly adapted


Possible Python translation
---------------------------

Here's a python transiteration attempt:

    #     ^:         ,       ~    ,.
    print rep(hook(vertcat, self(horzcat)),4)('*')

or slightly more idiomatic:

    def sierpinski(x):
        return vertcat(x,horzcat(x,x))

    print rep(sierpinsky,4)('*')

With:

    def identity(x): return x
    def rep(f,n): # f^:n
        if   n < 0: return lambda *args: rep(inverse(f),-n)(*args)
        elif n == 0: return identity
        else:       return lambda *args: rep(f,n-1)(f(*args))
    # horzcat and vertcat are only string-based special purpose mockups for this
    # problem since python doesn't have arrays
    def horzcat(a,b): # a,.b
        return "\n".join(a_i+b_i for (a_i,b_i) in zip(a.split('\n'),
        b.split('\n')))
    def vertcat(a,b): # a,b
        # fill "rows" of b up with spaces if a's rows are longer and vice versa
        dif = len(a.split('\n')[0]) - len(b.split('\n')[0])
        if dif < 0:
            a = a.replace('\n', ' '*-dif + '\n') + ' '*-dif
        elif dif > 0:
            b = b.replace('\n', ' '*dif  + '\n') + ' '*dif
        return a + '\n' + b
    def self(f): # f~
        return lambda x: f(x,x)
    def hook(f,g): # (f g)
        return lambda x: f(x,g(x))
    print rep(hook(vertcat, self(horzcat)),4)('*')

I find above J solution is quite neat conceptually because it directly
captures the self-similarity.

The other J solution is 

' *'{~2|!~/~i.*:2^4

Can you figure out how it works? (Hint: k!n = choose(k,n), 2|x = x%2)

'as



More information about the Python-list mailing list