Live data from Hacker News

Notation as a Tool of Thought

jsoftware.com

31–40 of 44 posts

Re: Notation as a Tool of Thought

#31
Iverson's famous paper introducing APL.

A key takeaway for me is that computers make it possible to have unambiguous notation. Quoting from Iverson's paper: "The thesis of the present paper is that the advantages of executability and universality found in programming languages can be effectively combined, in a single coherent language, with the advantages offered by mathematical notation."

Ambiguity is a real problem with much of conventional mathematical notation, which has evolved in fits and starts throughout history. Mathematical symbols are used, reused, and overloaded with different meanings again and again, in so many ways, that context is often necessary for understanding. Ambiguity hampers the use of mathematical notation as a tool for thought.

The other big takeaway from this paper, for me, is that succinctness makes it easier to reason. That is, programming languages that enable us to express more with less code make it easier for us to reason about -- and with -- code.

Re: Notation as a Tool of Thought

#32
post #30

Earlier quoted context omitted.

That can definitely be implemented in Matlab with the symbolic math toolbox. But interesting nonetheless.

I have used matlab quite a bit in the past, but not the symbolic math toolbox: can you make a "normal" function definition symbolic retroactively? I thought you need to define the function explicitly as symbolic to start with, or am I wrong?

Yes, the symbolic functions can be made "retroactively". The various conventional functions are overloaded with the symbolic input.

    >> syms x
    >> f = @(x) log(sqrt(x)).^2

    f = function_handle with value:

        @(x)log(sqrt(x)).^2

    >> f(x)
 
    ans = log(x^(1/2))^2
 
    >> finverse(f(x))
 
    ans = exp(2*x^(1/2))
And to implement under:

    function u = under(f, g)

    syms x

    g_inv = matlabFunction(finverse(g(x)));

    u = @(x) g_inv(f(g(x)));

    end

Re: Notation as a Tool of Thought

#33
post #30

Earlier quoted context omitted.

I have used matlab quite a bit in the past, but not the symbolic math toolbox: can you make a "normal" function definition symbolic retroactively? I thought you need to define the function explicitly as symbolic to start with, or am I wrong?

Yes, the symbolic functions can be made "retroactively". The various conventional functions are overloaded with the symbolic input. >> syms x >> f = @(x) log(sqrt(x)).^2 f = function_handle with value: @(x)log(sqrt(x)).^2 >> f(x) ans = log(x^(1/2))^2 >> finverse(f(x)) ans = exp(2*x^(1/2)) And to implement under: function u = under(f, g) syms x g_inv = matlabFunction(finverse(g(x))); u = @(x) g_inv(f(g(x))); end

So if you have odddouble.m with

    function y=odddouble(a,b)
       y=2*x+1
    endfunction
you can do

    >>> h = under(@(x) 1/x, odddouble)
    >>> h(3)
? If so, yeah, I agree you can implement under in matlab (as long as you have the symbolic toolbox as well); in which case it's probably one of very few non-CAS systems where you can define it.

Re: Notation as a Tool of Thought

#34
I have thought about this in relation to chess. Most of us play chess by looking at an 8x8 black-and-white grid with pieces on it. That is a two-dimensional notation capable of expressing any chess position (castling, en passant, repeat-moves etc, excepted).

What if you could invent a more efficient "notation" for chess? For example, FEN is a chess notation that is very efficient for computers. So maybe something similar exists for humans? Perhaps a three-dimensional notation, or perhaps a rearrangement of the board using knight moves and octagons instead of squares. Knights can jump in eight directions at most so a board using octagons would make it easy to see where they land.

Re: Notation as a Tool of Thought

#35
post #11

Earlier quoted context omitted.

If you think APL is less expressive than Matlab, you probably haven't really grasped it, IMO. Having said that, Matlab is optimized for manipulating matrices and replicating the notation of normal linear algebra and has excellent implementations of basically any numerical algorithm that frequently comes up in this . So writing something like chol(X'*X+diag(eig(X))) in an APL will look uglier and quite possibly slower…

> Admittedly the J implementation at least of deriving a generalized inverse for an arbitrary function f is a somewhat ill-defined hack Have you seen the version used by dzaima/apl[1]? The equivalent of '(-&.:{:) i.5' works and results in 0 1 2 3 _4. > APL has some really dumb but cherished-by-the-community ideas that make the language less expressive and much more awkward to learn, e.g. the idea of replicating the t…

Is there an argument for ambivalent function definitions other than "keyword" recycling (possibly in a mnemonic fashion)?

I hadn't seen Dzaima's APL, thanks! I like that he made a processing binding; APL always seemed like it would be such an obvious choice for doing dweet style graphics code golfing that I wondered why no one seemed to be doing it. A web-based APL would be a better choice though.

Re: Notation as a Tool of Thought

#36
post #35

Earlier quoted context omitted.

> Admittedly the J implementation at least of deriving a generalized inverse for an arbitrary function f is a somewhat ill-defined hack Have you seen the version used by dzaima/apl[1]? The equivalent of '(-&.:{:) i.5' works and results in 0 1 2 3 _4. > APL has some really dumb but cherished-by-the-community ideas that make the language less expressive and much more awkward to learn, e.g. the idea of replicating the t…

Is there an argument for ambivalent function definitions other than "keyword" recycling (possibly in a mnemonic fashion)? I hadn't seen Dzaima's APL, thanks! I like that he made a processing binding; APL always seemed like it would be such an obvious choice for doing dweet style graphics code golfing that I wondered why no one seemed to be doing it. A web-based APL would be a better choice though.

> web-based

In that case you'll be wanting ngn/apl[1], which runs in a browser and compiles to js.

> ambivalent

The arguments are mostly linguistic. Natural language is also context-sensitive, so we are well-equipped to parse such formations; and they allow us to reuse information. The monadic and dyadic forms of '-' are related, so it's less cognitive overhead to recognize its meaning.

1. https://gitlab.com/n9n/apl

Re: Notation as a Tool of Thought

#37
post #27

Earlier quoted context omitted.

You didn't mention it, so for avoidance of doubt: have you heard of k? Commercial k variants come with a columnar data store (see Kx's q/kdb+, Shakti's k9).

Yes, I heard of K which makes some things a little more convenient and others a little less by adopting the "list-of-vectors" model instead of true multidimensional arrays. K still is very much in the line of traditional APLs, though. I don't have extensive experience with K, but J with the Jd DB seems very closely related. I was thinking of more radical changes that would certainly disappoint APL purists by exchangi…

> endure the multiple weeks of effort required to learn the basics

J for C programmers is a good book - https://www.jsoftware.com/docs/help807/jforc/contents.htm - and it could take significantly less than many weeks to "get" some important ideas. Specifically, make sure you understand ranks at chapters 5 and 6.

After you understand how +/ with different ranks can sum along different axis, you're well on the way.

I mean, here is a cube of numbers:

       i. 2 3 4
     0  1  2  3
     4  5  6  7
     8  9 10 11

    12 13 14 15
    16 17 18 19
    20 21 22 23
Plain +/ sums along the leading axis -

       +/ i. 2 3 4
    12 14 16 18
    20 22 24 26
    28 30 32 34
That's because rank of +/ is infinity, so / inserts pluses between highest-ranked items, of which there are two - a square

     0  1  2  3
     4  5  6  7
     8  9 10 11
and square

    12 13 14 15
    16 17 18 19
    20 21 22 23
(rank is a sort of dimension). So +/ just adds, element by element, these two squares together, giving the resulting square.

If you specify +/"0 - this sets the rank of the verb (function) to 0 - then +/ will be applied to each number separately and results will be combined. Adding a single number (not with itself - just as it is, without the other argument for summation) makes the same number, so +/"0 doesn't change the result - it's the same cube as in i. 2 3 4

Trying with +/"1 gives

       +/"1 i. 2 3 4
     6 22 38
    54 70 86
That's because +/"1 now is a verb of rank 1, so it works with items (subarrays) of rank 1. In cube i. 2 3 4 there are 6 subarrays of rank 1, 3 of them are in the first "plane" and 3 of them are in the second "plane". +/"1 takes each such subarray of rank 1 separately and sums elements in it (inserts + between elements of such array), and J then aggregates results into the array.

Finally,

       +/"2 i. 2 3 4
    12 15 18 21
    48 51 54 57
sums within 2-dimensional arrays. Elements of such arrays are 1-dimensional arrays, so those arrays are summed, element by element. There are two planes, so the result has two element (two arrays of rank 1), and each element is array of rank 1, obtained from summing 3 arrays of rank 1.

The book tells it better, of course.

Re: Notation as a Tool of Thought

#38
post #9

For those unfamiliar with the power of APL, see this demo of someone livecoding the Game of Life: https://www.youtube.com/watch?v=a9xAKttWgP4 Its modern descendent are https://en.wikipedia.org/wiki/J_(programming_language) & https://en.wikipedia.org/wiki/K_(programming_language) .

APL was amazing for the time, but array-oriented programming is mainstream now, while the notation never really caught on. A lot of the mystique of APL is because it's illegible, but at the end of the day it's nothing more than a DSL for 'numpy-like' code. You can code the same demo, in the same amount of time, using Julia, and the result is (in my opinion) much more legible:

The opaque one-liner:

using IterTools,ImageInTerminal,Colors;for g in iterated(a->let n=sum(map(t->circshift(a,t),product(-1:1,-1:1)));(a.&(n.==4)).|(n.==3);end,rand(Bool,(99,99)));imshow(map(Gray,g));print("\n\n");end

The legible version where we give everything descriptive names so it's not cryptic and mysterious:

  using ImageInTerminal,Colors #the APL demo also uses a library for pretty display
  using IterTools #okay *technically* this is a minor cheat

  function nextgen(grid)
        neighborcount = sum(map((t)->circshift(grid,t), product(-1:1,-1:1)))
        return (grid .& (neighborcount .== 4)) .| (neighborcount .== 3)
  end

  function animate(grid)
        for gen in iterated(nextgen, grid)
                imshow(map(Gray, gen))
                print("\n\n")
                sleep(0.05)
        end
  end

  animate(rand(Bool,(100,100)))

Re: Notation as a Tool of Thought

#39
post #38
post #9

For those unfamiliar with the power of APL, see this demo of someone livecoding the Game of Life: https://www.youtube.com/watch?v=a9xAKttWgP4 Its modern descendent are https://en.wikipedia.org/wiki/J_(programming_language) & https://en.wikipedia.org/wiki/K_(programming_language) .

APL was amazing for the time, but array-oriented programming is mainstream now, while the notation never really caught on. A lot of the mystique of APL is because it's illegible, but at the end of the day it's nothing more than a DSL for 'numpy-like' code. You can code the same demo, in the same amount of time, using Julia, and the result is (in my opinion) much more legible: The opaque one-liner: using IterTools,Ima…

I would argue that numpy is a dsl for apl-like code. APL and J are based on arrays at the fundamental level. J inspired Pandas per Pandas' creator.

I still think learning mathematical symbols is better than spelling out mathematical formulas and likewise APL and J to me allow the same power of abstraction; it just takes some effort to learn them. A lot of friction is learning something new.

Re: Notation as a Tool of Thought

#40
post #33

Earlier quoted context omitted.

Yes, the symbolic functions can be made "retroactively". The various conventional functions are overloaded with the symbolic input. >> syms x >> f = @(x) log(sqrt(x)).^2 f = function_handle with value: @(x)log(sqrt(x)).^2 >> f(x) ans = log(x^(1/2))^2 >> finverse(f(x)) ans = exp(2*x^(1/2)) And to implement under: function u = under(f, g) syms x g_inv = matlabFunction(finverse(g(x))); u = @(x) g_inv(f(g(x))); end

So if you have odddouble.m with function y=odddouble(a,b) y=2*x+1 endfunction you can do >>> h = under(@(x) 1/x, odddouble) >>> h(3) ? If so, yeah, I agree you can implement under in matlab (as long as you have the symbolic toolbox as well); in which case it's probably one of very few non-CAS systems where you can define it.

Just tested it and it worked fine. Note that your function takes too many parameters in its definition and that functions can't be passed as parameters by name.

It is definitely not as elegant as the built-in facility in J, but definitely doable and usable in Matlab. In fact, I think any language with flexible enough function overloading should be able to implement such a feature.

Post reply on HN