
Julia as a CLI Calculator - krjt
https://krasjet.com/rnd.wlk/julia/
======
dgb23
This seems to be a very neat intro into Julia and a practical use case. I’ve
been postponing to learn the language for a while now, but from what I
heard/seen it seems to be extremely well designed.

~~~
jweir
I used it as my CLI calculator, just like the articles title. I used to use
Ruby for this, but Julia is more concise but still readable. Concise enough I
have written useful applications that can fit in a tweet.

------
enriquto
I love the julia language. I would love to use julia as a command line
calculator. Unfortunately, starting the interpreter is excruciatingly slow, an
order of magnitude slower than octave or python (and several orders of
magnitude slower than bc or dc).

~~~
dunefox
Simply loading the REPL takes half a second for me. I use it all the time as a
simple calculator.

~~~
enriquto
> Simply loading the REPL takes half a second for me. I juse it all the time
> as a simple calculator.

Half a second is precisely what is meant by "excruciatingly slow". If I need a
simple calculator, I expect to be able to use it to compute intermediary
results in a shell loop. If my loop has one thousand iterations, you are
spending about 10 minutes just initializing the interpreter. This is absurd.
Of course, you can rewrite your whole loop upside down, so that the
interpreter is called outside the loop. But this kind of defeats the goal of
considering julia to be a general-purpose calculator, orthogonal with its
usage patterns.

~~~
socialdemocrat
> If I need a simple calculator, I expect to be able to use it to compute
> intermediary results in a shell loop.

No offense but that must be one of the dumbest ideas I have heard in a long
time. The reason you write something in a shell script is because it is
portable on all Unix systems. If you add a dependency to a particular
programming language like Julia, then that portability is out the windows. You
require installing users to install Julia first.

If you require users to install Julia, you might as well ditch the shell
script all together. All shell languages suck anyway for anything non-trivial.

I have rewritten plenty of shell scripts to Julia. It is much faster to write.
The code is easier to read and understand and it executes way faster than any
shell script.

Running a complicated shell script that calls out to Julia 1000 times makes
absolutely NO SENSE! It is a completely contrived example with no practical
application.

Besides when people say "calculator," I think most reasonable people assume an
interactive system for doing calculations, not a glorified math library. Julia
offers a great interactive environment for doing calculations.

~~~
enriquto
> No offense but that must be one of the dumbest ideas I have heard in a long
> time.

Thanks. This is not the first time I've been told that.

> The reason you write something in a shell script is because it is portable
> on all Unix systems.

This is definitely not my case. I write plenty of shell code at work, but
rarely distribute it. It is just for arranging data around, preparing one-off
experiments, and so on.

> Running a complicated shell script that calls out to Julia 1000 times makes
> absolutely NO SENSE!

I agree that this may be a rare use case, but it is legitimate nonetheless.
Moreover, the best tools are those that can be used successfully in ways that
the creator of the tool would find abhorrent.

> It is a completely contrived example with no practical application.

This was a concrete example actually. I had a shell script that cropped,
denoised and registered a collection of a few thousand photos scattered in a
directory tree. It was a four-line pipeline that called a few command line
tools from imagemagick and gmic to do the image processing work. At one point,
I realized that I had to apply an homography to the images (given by a 3x3
matrix that was stored as 9 numbers in a text file) to map them to a different
coordinate system. This involved a 3x3 matrix multiplication for each image. I
did this multiplication in julia, my favorite calculator. The running time of
the whole thing went from 10 to 20 minutes. Doing the "correct" thing and
rewriting everything in julia would be extremely painful.

> Besides when people say "calculator," I think most reasonable people assume
> an interactive system for doing calculations

When you say "CLI Calculator", you can also think about a calculator that you
can call from your shell command line. This is the case for example for the
classical calculators bc(1) and dc(1), which are non-interactive, and
purposefully intended to be called inside loops in a shell script.

~~~
dunefox
> Doing the "correct" thing and rewriting everything in julia would be
> extremely painful.

Not necessarily: [https://docs.julialang.org/en/v1/manual/running-external-
pro...](https://docs.julialang.org/en/v1/manual/running-external-programs/)

~~~
enriquto
That's great! I didn't know about that

------
jaquers
The typography in this post is beautiful (as well as the content), anybody
know where this comes from? Did the author do it by hand or is it something
off the shelf?

Asking for a friend...

~~~
krjt
The styling is done from scratch.

For more information, see the colophon [1] and karasu [2].

[1]: [https://krasjet.com/colophon/](https://krasjet.com/colophon/)

[2]: [https://github.com/Krasjet/karasu](https://github.com/Krasjet/karasu)

~~~
jaquers
Nice job!

------
oefrha
I use Mathematica as my advanced calculator. It’s a functional language with
an extremely vast and consistent mathematical and non-mathematical library,
top notch symbolic capabilities (SymPy is just child’s play in comparison),
top notch numerical capabilities, and very decent performance. You certainly
don’t need to write your own rotation function — well, 2D rotation is trivial,
but what if you want 3D rotation around a vector? Mathematica’s got you
covered. Got a command line mode too, see MathKernel.

The downside: it’s not free (as in beer or speech).

~~~
cytzol
I know it's a very general question, but can I ask what sort of calculations
you perform using Mathematica? Every time it has a new release, I download the
demo and play around with it, but I never get as far as using it to actually
_compute_ anything that other CLI calculators couldn't do.

~~~
oefrha
I’m a physicist so all kinds of numerical and symbolic calculations, e.g. very
complicated integrals, differential equations, integral equations, and so on.
I also work on math problems either seriously (way back when I was an
undergrad I worked on some number theoretical problems where computational
insight is very important) or for fun (think Project Euler style problems).

If you just need to a calculator to do everyday arithmetic or unit
conversions, or even simple physics calculations with units, it’s serious
overkill... I certainly hardly ever need it when I’m wearing my programmer
hat.

I guess to answer is that the boundary between a calculator and a full blown
computational environment is very blurry to me.

------
ohsonice
I've been using Julia as my CLI calculator for a few years now - cool to see
this post! While teaching an online Linear Algebra class, I would use Julia to
construct examples and quickly solve them. The syntax sugar of all the
functional idioms make it very fun and easy to express more complicated ideas.
This is a cool introduction- I was not aware (or had forgotten) about function
chaining. Really curious about using more of Latexify as well :)

On an unrelated note, (as a mathematician) I have started using Maple a lot
more as my analytic computational helper. Never really gave it the time of day
in years past - it is quite powerful and intuitive. Funny note: I recently
copied and pasted output of a Maple command into my Julia code and it was
syntactically correct!

------
knight17
Since this is a calculator topic, I'd like request your input on which
calculators you use.

I use the Emacs calculator (M-x calc) and XCalc
([http://www.tordivel.no/xcalc/](http://www.tordivel.no/xcalc/)) as I like to
use RPN calculators. The Windows 10 calculator is painful and slow. XCalc has
a mini mode, where it will sit as a small, single line without distracting you
too much. I like that feature very much.

One thing with Emacs is that I forget the shortcuts for non-frequent
calculations that I'd have to go and search for it.

~~~
ibiza
I use a function "ev" that wraps bc. It's crude, but handy:

    
    
        $ ev() { echo "scale=3; $*" | bc -l; }
        
        $ ev 22/7
        3.142

~~~
geraldcombs
I do something similar, with a couple of convenience substitutions for commas
and multiplication:

$ math() { echo "scale=2 ; $ _" | sed -e "s:x:_:g" | sed -e "s:,::g" | bc; }

$ math 5,382 x 48,927.3

263326728.6

~~~
majewsky
You should put this into a codeblock by indenting by 2 spaces. The formatting
converts asterisk-delimited text into italics.

    
    
      $ math() { echo "scale=2 ; $*" | sed -e "s:x:*:g" | sed -e "s:,::g" | bc; }
      
      $ math 5,382 x 48,927.3
      
      263326728.6

------
nsajko
A problem with Julia is that it does not parse input numbers with arbitrary
precision by default. Example:

    
    
      julia> sin(1.461920290375737576933544899379e+31)
      -0.9468766486679395
    
      julia> sin(parse(BigFloat, "1.461920290375737576933544899379e+31"))
      0.6864670207863400975666631018263839509022548965872940746039593018855528710432756
    

Fricas is better in this regard, some links:

[https://en.wikipedia.org/wiki/FriCAS](https://en.wikipedia.org/wiki/FriCAS)

[https://fricas.github.io](https://fricas.github.io)

[https://github.com/fricas/fricas](https://github.com/fricas/fricas)

[http://www.euclideanspace.com/prog/scratchpad/fricas/](http://www.euclideanspace.com/prog/scratchpad/fricas/)

EDIT: some info about FriCAS: it's implementation is currently based on Common
Lisp, on top of which a language called "Spad" (short for Scratchpad) is
implemented. Fricas is a fork of the Axiom computer mathematics system, which
in turn is a continuation of Scratchpad. EDIT: and, at least with SBCL, it can
use GMP for bignum.

I only skimmed the article, but I believe Fricas supports all uses of Julia
mentioned in the article, and more, like advanced symbolic integration.

~~~
johnmyleswhite
It seems like it would be pretty easy to make a REPL mode that did the big
conversions automatically. Not sufficient to protect a naive user, but
arbitrary precision floating point is never safe.

~~~
nsajko
> arbitrary precision floating point is never safe

Care to expand on that? Are you advocating for interval arithmetic or maybe
decimal floating point?

For what it's worth I think that one would rarely need to interactively deal
with so much data at once that using, say, 10000 bit binary floating point
would be prohibitive. It is difficult to lose the necessary significant digits
with so much "safety margin", and one still has space for about a million of
such high-precision floating point numbers.

~~~
johnmyleswhite
I agree with your assertion that most users could get away with 10,000 bits.
My point is only that there's always going to be somebody who still tries to
do something that fails, so you have to pick some set of tradeoffs. Yours
seems reasonable.

------
fsloth
Oh, brilliant! This is exactly what I've been looking for. Didn't realize the
syntax was so succint. So far I've preferred excel for my multidimensional
calc needs but this fits my needs exactly (need to do simple back-of-the-
envelope vector calculations time to time).

------
RivieraKid
I really wish there was a language based on Swift that would include most of
the nice language, REPL and library characteristics of Julia (and perhaps few
from Dart). That would get really close to a "perfect language" for me.

Overall I like Julia - and use it as a CLI calculator as well - but there are
several things that prevent it from being a good general purpose language:

\- OOP support is "meh".

\- str.parse(Int).abs is more readable than abs(parse(Int, str)). And this is
a very simple case, the readability difference is greater in more complex
expressions.

\- 1-based indexing.

\- Lack of good support for nullability, think of "if let", "guard let", "??",
"object?.property".

\- There are some more, this is just from the top of my head.

EDIT: A better example of why Julia's syntax is less readable:

`images.first.resize(100, 100).crop(25, 25, 75, 75)`

versus

`crop(resize(first(images), 100, 100), 25, 25, 75, 75)`

~~~
dnautics

        crop(resize(first(images), 100, 100), 25, 25, 75, 75)
    

this will likely get better when julia implements proper pipes, IIRC coming
soon in the plans (like elixir does):

    
    
        images
        |> first
        |> resize(100,100)
        |> crop(25, 25, 75, 75)
    

If the language bothers to implement an inspect method (again, like elixir)
this is vastly superior to . chaining because you can do this:

    
    
        images |> inspect
        |> first |> inspect
        |> resize(100,100) |> inspect
        |> crop(25, 25, 75, 75) |> inspect
    

trivially with multiline cursor (and also trivially ninja'd out with multiline
cursor) and have full introspection on the evolution of your data through the
pipeline. This is impossible in oo languages (well maybe you could do it in a
prototyped language) because dispatch of the .inspect method would have to be
implemented on each object.

~~~
jessebett
I'm not sure what `inspect` does, but can you clarify what you mean by proper
pipes?

    
    
      julia> x = [3,2,4,5]
      4-element Array{Int64,1}:
       3
       2
       4
       5
    
      julia> x |> sort |> x->reshape(x,(2,2))
      2×2 Array{Int64,2}:
       2  4
       3  5
    

works.

It gives a syntax error if the pipes are on the newline. Is that your gripe?

Or is it that it doesn't automatically partially apply the function, requiring
you to use an anonymous function, like `x->reshape(x,(2,2))` instead of as you
have it `resize(100,100)` implicitly. I prefer the explicitness.

~~~
dnautics
Yes, by "proper pipes" I mean partial application. (I used to code julia but
now I'm mostly living in elixir because that pays the bills) Yes, the
explicitness of what you wrote is a marginal gain in preferability from an
idealized point of view, but I promise you your eyes and brain will be more
tired from that explcit form than if you just learn to read pipelines as
passing into the first value (in elixirland we have lambdas that you can pipe
into, too. Nobody does this.)

You don't know what you're missing by not having an inspect function. In
elixir it's styled "IO.inspect", and it pretty-prints the value as a side-
effect, and returns the value unchanged. You can pass a "label" option as your
second parameter, and that will add a label to the pretty print. For example,
assume I have a module M with the expected functions:

    
    
        value = 10
        |> M.add_3 |> IO.inspect(label: "A")
        |> M.times(4) |> IO.inspect(label: "B")
        |> M.minus_2 |> IO.inspect(label: "C")
    

will print:

    
    
        A: 13
        B: 52
        C: 50
    

and value will be assigned 50.

Now, the great thing about that is that you can blat a bunch of IO.inspects
simultaneously using multiline cursors. That low friction 1) causes you to
actually use it, and 2) cause you to also set your code up so that it's easy
to IO.inspect, which typically also means cleaner, and easier to read code. It
is IMO the most powerful debugging tool that I've ever used.

Example:
[https://github.com/ityonemo/ex_dhcp/blob/master/lib/ex_dhcp....](https://github.com/ityonemo/ex_dhcp/blob/master/lib/ex_dhcp.ex#L355)

That small pipeline does a pretty complex set of actions - deserialize a raw
binary to a structured datatype, then call a handler, then process a handler
return result. There are four datatypes that run through that pipeline.
Nonetheless, I can inject IO.inspects into that with six keystrokes (I have a
vscode snippet), run the code, and watch as the data are transformed, and
immediately identify what corner case I missed and write a proper test for it.

And yes, it is far less powerful if the pipes can't tolerate the newline.
(though you usually can still multicursor on a single line).

Anyways, I'm not saying this to rag on Julia. I'm just saying I think julia
can and SHOULD have this, and it would be awesome. Also, elixir needs to learn
a thing or two from julia's repl.

------
cycomanic
One of my main gripes about matlab and that Julia unfortunately adopted is the
dot syntax. Any other symbol would have worked, but the dot is just way too
easy to overlook.

I think it is because it was initially developed for people primarily working
with matrices.

Most of the things I do is actually based around multidimensional arrays so
when I do operations I almost always want element-wise operations.
Unfortunately you often don't even realise you do the wrong operation, just
the result is wrong. So I have spend lots of time debugging, until I realised
I had a missing dot somewhere, and then spending again significant time trying
to find where the dot is missing.

I therefore always found the complaint about np.dot(x,y) being too verbose
interesting, because I like that, it makes it explicit and is difficult to
overlook.

~~~
dklend122
You can use the @. macro to dot an entire block.

I personally like the dot syntax. It's ergonomic, and provides cool stuff like
this:
[https://julialang.org/blog/2017/01/moredots/](https://julialang.org/blog/2017/01/moredots/)

I don't know of an equivalent functionality in any other language.

~~~
cycomanic
The @. syntax is definetly an improvement. I don't have an issue with the
principle of the dot syntax just with the symbol. The examples in your link
perfectly illustrate the issue. If this was a line in a long code base maybe
even with mixed element-wise and matrix operations it would be very easy to
overlook a missing dot. It would be even worse if the constants were floats.
It is just such a terrible choice of symbol for this operation, because it is
so easy to overlook.

Everyone I know always looks for missing dots if they encounter a some
nonstraight forward bug in matlab (I don't know any Julia users).

------
plashchynski
I've been using Julia REPL as s scientific calculator for a few months. I'm
impressed how wonderful it is. Thank you for the article!

------
starpilot
One thing I miss is RPN-string input. Unlike normal RPN where you load the
"stack," for RPN string you can enter

> 2 3 + 4 *

as one line, press enter, and get 20. This lets you take advantage of the no-
parens nature of RPN while viewing the expression on one line rather than
flipping through the stack. Only Windows PowerToy scientific calculator had
this mode, that I know of.

~~~
CamTin
this sounds like "dc" except with dc you'd need to add a "p" at the end to
print the top of the stack

~~~
starpilot
I had never even heard of dc. This is a lifesaver.

------
cormullion
This is a great article - interesting, well-written and beautifully presented!

A minor quibble in the typography - the use of small caps for every initial
letter is slightly catching my eye every time I see it. Perhaps I don't see
enough similar typography on the web to make it feel more natural ¯\\\\_(ツ)_/¯
...

------
krzyk
I use python CLI for exactly the same :)

~~~
Hamuko
I used to use Python REPL for that until I switched to fish shell. Now I just
run

    
    
        $ math "999.999 / 3"
        333.333
    

Granted, I don't really do any complex calculations in my terminal.

~~~
shreyasminocha
> Granted, I don't really do any complex calculations in my terminal.

Same. I use insect —
[https://github.com/sharkdp/insect](https://github.com/sharkdp/insect)

------
DreamScatter
Nice article! I'm the creator of the Grassmann.jl package, which was mentioned
in the article :)

------
seltzered_
I wonder if it'd be possible to have a blend between this and
[https://calca.io](https://calca.io) where the repl output appears (and change
dynamically) as specialized comments within a markdown-friendly format.

------
rscho
Julia is nice for scientific serious work, but for cli calc J (jsoftware.com)
really rocks!

------
bryanrasmussen
from EasyJ
[https://www.jsoftware.com/books/pdf/easyj.pdf](https://www.jsoftware.com/books/pdf/easyj.pdf)

J in its simplest use acts just like a desk calculator.

If you are working at a terminal, type the following input, pressing the
“enter” key after each line :

    
    
       3+4 
    

7

    
    
       5*20 
    

100

------
29athrowaway
My personal choice for this is Jupyter and Sagemath.

~~~
wbhart
SageMath takes 3s to load for me (sometimes a lot more if my systems
administrator has updated it recently, which seems to happen a lot).

I therefore use Pari/GP for my personal choice. I like the symbolic nature of
Pari/GP over Sage or Julia, even though I spend nearly all of my life
programming in Julia, and love the language a lot.

However, for computations of trivial things that I want to run really fast, I
put them in a function in Julia (so that they are jit-compiled), since nothing
will come close to that, by some orders of magnitude.

------
dan-robertson
My main calculator is gnu calc which is the calculator built into emails. It
tends to hit various ceilings where it can’t go much further but it has lots
of nice features:

1\. The data I want to work with tends to be in my text editor so it makes
sense to have the calculator there too. Macros can be used to fix up
formatting to input numbers

2\. Speed of input makes it so much nicer to use. If I look at the examples in
the article, here is a comparison. Julia:

    
    
      7 / 4
      x = ans + 2 im 
      exp(x)
      A = [...]
      A * [...]
      [a^2 for a \in A]
    

Emacs:

    
    
      7 RET 4 /
      (0,2) + s t x (but I probably wouldn’t use a variable)
      s r x E (if I used the stack this is just “E”)
      [(same but RET or , not SPC)] s t A
      s r A [...] *
      s r A V M I Q (that’s vector map inverse square root)
    

These examples make emacs look bad because I’ve replicated saving things to
variables it actually I’d just use the stack. I guess in Julia you can press
the up arrow. There are other examples like 1 |> exp |> sin is just 1 E S in
Calc (and those operations broadcast over vectors automatically, although I
think emasculated does the right thing and doesn’t broadcast exp over
matrices).

Skipping the massive tangent of non-calculator things about Julia, we move on
to a discussion of plotting. There isn’t a Unicode-art plotting mode in emacs
because we have had graphical terminals for over 30 years. In emacs you plot
with g f and can then modify your plot with other commands. In just about
every language you need to call a function called plot so you’re already
losing on characters before you’ve even started. If plotting is fast and easy
then exploration is easy.

3\. The calculator has lots of useful features that fit well together.
Plotting is built in. As are unit conversions, a bunch of symbolic algebra
(simplification, differentiation, basic integration, curve fitting, solving
equations, numeric integration/solutions, and a super nice facility for
editing expressions). There’s a bunch of other functions for stats, vectors
(both linalg and things like map/reduce), number theory, physics, etc. There
are language modes for things like latex output too. Most stuff works on a
bunch of number types (bigints, rationals, arbitrary precision floats,
infinity, intervals thereof, complex numbers, error forms, symbolic
expressions, dates)

4\. I want to reiterate the point about speed. The thing I care about being
fast is telling the computer what to do. It takes basically 0 time to do most
mathematical operations so latency is dominated by input. So even though emacs
uses interpreted emacs lisp and doesn’t even use hardware floating point
numbers, it still feels faster than Julia with its optimising JIT. If I want
to do something with a large amount of data then I can either wait a few
seconds or realise that I’ve gone beyond calculator work and use something
better suited.

I think Julia is a great language and it has great advantages over emacs for
numerical computing. A big one is that the language and type system is much
more naturally extensible for this sort of thing. But I don’t feel that it
makes a particularly good calculator. The main reason to think that it is a
good calculator is that the alternatives (bash/bc/python/matlab) are so bad.

