In Common Lisp:
CL-USER 37 > (sin 3)
0.14112
CL-USER 38 > (cos *)
0.9900591
Above is acually is (cos (sin 3)). The variable * is bound to the last result.When used interactively, Python also has _ to store the previous value (but Python only ever really returns single value, which is sometimes a tuple or a list that can be deconstructed into variables, iirc in CL if you don't request other return values, they are gone.)
More generally, you'd want more of xargs-like functionality (eg. split result into chunks and feed them to the next function in chunks, perhaps in parallel). Or maybe you'd want something like a tee, to split the results of the previous function into multiple streams and processed by different functions? Java-like languages don't immediately support something like that, but Shell-like do with redirection syntax, tee, xargs.
But in Lisp you are not bound to the language syntax of Java. You can inside the language write tools to process forms. That's one of the main differences between Java and Lisp. Lisp has reader macros (to change the surface syntax of s-expressions) and macros to change the expression syntax. That would allow you to write tools to process code and results in arbitrary ways.
Multiple-values results in a REPL are handled by the variable /. That one is the list of the last values.
CL-USER 4 > (values 1 2 3)
1
2
3
CL-USER 5 > (multiple-value-bind (a b c) (values-list /) (list a b c))
(1 2 3)
But anyway, I would not write Common Lisp in a pure terminal without editing support.Something like GNU Emacs can use tools like SLIME or has a SHELL mode. That one works fine in a terminal.
SLIME is one of the Common Lisp IDE extensions for GNU Emacs and works fine in a terminal. Writing even the most complex code inside an GNU Emacs & SLIME terminal session is no problem at all. If I have a function call (foo a) and I want to wrap code to the front, I would just move the cursor one s-expression back and type. I'm sure that's easier with one of the other editor extensions which make editing s-expressions kind of structural.
EVEN then, many people write the actual Lisp code in an editor buffer (say GNU Emacs in a terminal connected to a Lisp process via SLIME) and send the expression for evaluation to a connected or underlying interactive Lisp sessions. The editing of s-expressions in a terminal to move forward, backward, upward, etc is really a non-issue.
Interactive read-eval-print-loops does not mean one is forced to use a terminal without editing support.
Anyways, the problem with handler-case still stands, as well as the other aspects s.a. chunked output, tee and redirects. It's something that would have to be programmed on top of the existing stuff, which was my point originally.
That's one thing I will say after coming from Perl/PHP to Java, is that despite its verbosity and the uselessness of having to write .stream(), I much prefer Java's stream.map(...).filter(...) syntax over the more functional-style filter(map(list, ..), ..) syntax. The Java syntax reads left-to-right, which is the order you want when you're thinking about code, and also as you say writing it. I think if I were creating a programming language I too would try to make stuff read left-to-right as much as possible.
Of course, Ruby is a bit of a mixed bag, but for the applications where it fits, it can be very nice.
@source >>> map { ... } >>> grep { ... } >>> my @sink;
though note I'm typing from memory on my second coffee so I may have got that slightly wrong.Plus of course there's many languages with a |> operator so you can do
g(x) |> f
I also (the example is specialised for I/O but the implementation technique could trivially be borrowed for something that wasn't) implemented something sort of in this direction for perl once: http://p3rl.org/IO::PipelineI'm not convinced that left-to-right is -always- the best option and prefer having the choice of both, but I wouldn't be at all surprised if a survey of developers found that if they could only pick one they'd pick left-to-right, and while I'd find it hard to choose for myself alone I'd probably pick left-to-right on the basis that it'd likely make it easier to onboard people to any given codebase.
my @sink = @source.map({...}).grep({...}).sort;
Which also makes multithreading the operation easy: my @sink = @source.hyper.map({...}).grep({...}).sort.list;
That said, I think the operator you're looking for is the feed operator, ==>: my @sink;
@source ==> map {...} ==> grep {...} ==> sort ==> @sink;
It also has the corresponding reverse, <==, because why not. The docs* mention that ==> may at some point do automatic parallelization, but I don't know what the status of that feature is.Yes, yes it was.
Clarifications and elaborations much appreciated.
That's why I use and msybe tend to abuse the `->` and `->>` macros in Clojure and the pipe operator `|>` in Elixir.
Hopefully soon in JS as well, if I've read correctly.
So I added postfix function application. So instead of (f (g x)), you can write (g x | f).
I liked the syntax a lot, but it looked really weird with operators: (calculate x | + 1). So I made operators automatically infix: (calculate x + 1).
I also didn't like that the transformation from foo to (foo :something) (record field access) required going back and adding parentheses before the value, so I added foo.something syntax that means the same thing.
The result is something that's very easy for me to type and read:
(def eyes
(eye-shapes
| color (c + 0.5)
| color (c - (dot normal (normalize eye-target) - 0.72
| clamp -1 0
| step 0))
| color [c.b c.g c.r]))
(Excerpt from the logo of https://toodle.studio -- https://gist.github.com/ianthehenry/612c980f0db04ea3c2ccab27...)Is this even Janet anymore? I dunno. It's a Janet dialect, and it's implemented as regular old Janet macros. But it's much easier for me to type like this. I recognize that it makes my code necessarily single-player, but that's fine for the sorts of dumb projects that I do for fun.
I think a lot of lisp programmers use paredit exactly so that they can write (f (g x)) in the order g x f, but with their editor re-positioning their cursor and taking care of paren-wrapping automatically. But I don't use paredit, and I don't want to wed myself to a particular mode of editing anyway. So I like a syntax that lets me type in the order that I think.
It's really just about readability preference though not ease of editing, lisp like languages will have paredit/sexp editing shortcuts in your editor, so when you're on (f x), you press one key and it's turned into (<cursor here> (f x))
I like Lisp languages, and would take Scheme over Python for my job in a heartbeat, if I was allowed to. But, I think, that if we want interactive Shell-like programming, we really need to address the issues above in the language. Shell pipes are a good start, but they are quite restricted in what they can do and require xargs "extension". Some languages also have the "where" form, where arguments to a function can be elaborated after the function call.
If I was ever to design a language for interactive programming, I'd certainly try to have these two features in it.