4 ms·
It's a functional programming language where every function is of type stack -> stack. I like concatenative languages[1] and especially pipelines[2], but IMO F
by nivertech 6y ago
It's a functional programming language where every function is of type stack -> stack.
I like concatenative languages[1] and especially pipelines[2], but IMO Forth-like stack-oriented languages are in the wrong direction, b/c they force programmer to manipulate arguments on a stack, which feels hackish.
And my first real physical computer was an RPN calculator. As a kid I wrote lots of programs for it.
Also b/c of their simple implementation, Forth-s and stack-based VMs are frequently used in the wrong domains, i.e. Bitcoin's Scripts and Ethereum's EVM.
APL-family languages are better in this regard, but they also feel hackish in the general case, especially when passing arguments to nested functions.
Copying RTL-style from math notation is also wrong. You are typing LTR (at least in English), but the expressions are evaluated RTL. Here Forth, RPN, and UNIX pipelines got it right.
The interesting direction would be a programming language with following attributes:
- Purely-functional
- Statically typed with an algebraic type system
- Concatenative [1]
- Tacit / Pipelines [2]
- Homoiconic
- top-to-bottom, LTR
[1] https://en.wikipedia.org/wiki/Concatenative_programming_language https://en.wikipedia.org/wiki/Concatenative_programming_lang...
[2] https://en.wikipedia.org/wiki/Tacit_programming https://en.wikipedia.org/wiki/Tacit_programming
- vanderZwan 6y agoI think your list basically describes http://kittenlang.org/ http://kittenlang.org/ which sadly has kind of halted in development because the sole dev working on it couldn't get anyone else on-board. Probably because it occupies a pretty rare niche of computer science interests.
- nivertech 6y agoany relation to Cat [1]? [1] https://web.archive.org/web/20150205081218/http://cat-language.com/manual.html https://web.archive.org/web/20150205081218/http://cat-langua...
- vanderZwan 6y agoIt's a direct inspiration - hence the name ;)
- thelazydogsback 6y agoI appreciate both Forth (and Lisp) and have both used and implemented several (mostly naive) versions of both, but IMHO with something OCaml/F#/Reason you get pretty close. Sure, it's not concatenative, but you can certainly code point-free if you like so rather than: c(b(a(42), 2)) You can write either: 42 |> a |> b 2 |> c or a reverse pipeline: c <| b 2 <| a <| 42 with complete type-safety. Note quite as concise as: 42 a 2 b c But I that's good for the most part. I think programming with higher-order curried functions and closures gives similar power but much more readability -- every time I've gone past the toy program stage with concatenative languages, my head ends up exploding -- but maybe I never had the appropriate epiphany. With that said, I certainly appreciate the power of Forth and compile-time words -- amazing power for such a minimal system.
- nivertech 6y agoagree, I'm using pipelines in Elm, which is almost the same syntax as in OCaml (piping into the last argument). I dislike "<|" b/c of the flexibility syndrome. It's frequently used in Elm in order to avoid parentheses. Same with Elixir, but it's missing currying, so it does piping into the first argument. Clojure has both thread-first and thread-last macros. The problem with these approaches is that they are optional. Ideally the point-free programming will be the default, not an optional style. I agree that pipelines in Elm and Elixir are much more readable than point-free code in Forth and APL ;) Unlike the ML-family languages, in APL/J/K/q you can omit any combination of arguments: f:{x-y} f[1] same as f[1; ] f[;1] same as f[ ;1] f same as f[ ; ]
- thelazydogsback 6y agoMost Lisps (incl. clojure), Scala, and probably others also allow placed or numbered "holes", so something like: 42 |> f 3 would be the same as 42 |> f 3 _ but you could do: 42 |> f _ 3 to get at the first arg. or even to swap args: 42,43 ||> f %1 %0 which would essentially get expanded to: 42,43 |> fun a b -> f b a (Of course, in this case the closure should get erased by the optimizer to simply "f 43 42".) I really miss not having this in F# (and C# for that matter)
- ken 6y agoI’m not sure what “feels hackish” means but it sounds suspiciously like a nonspecific complaint that is used when all the actual potential issues have been exhausted. In programming, we’re always dealing with stacks. It’s just that they’re usually invisible. As someone dealing with an unexpected user crash in a modern/traditional language, the possibility of making them visible would be pretty helpful right about now! I’d kill for a crash dump that included a data stack, too.
- andrewflnr 6y agoIt's an aesthetic complaint. It has the word "feels" right in it. What do you expect? With that said, as someone who hasn't programmed in Forth-likes but has read about them, I can guess at a more precise complaint: stack manipulation operations like dup, swap, roll, et al are pure noise relative to my business logic. They're implementation details constantly interfering with my intent. And yes, I'm sure if I find just the right factorization into tiny words I could avoid most of the explicit stack twiddling, but is that really a good use of time relative to writing in C? Or figuring out how to design a better language? Doubtful.
- nivertech 6y agoCorrect, there are lots of abstractions under the hood it doesn't mean they need to be intertwined with our business logic. What's next exposing the microcode or physical RAM layout? Even worse majority of ISAs are register-based, not stack-based. So this abstraction is virtual. What I meant is that Forth wasn't designed from first principles. Instead of solving the problem "how to help developer to transform business logic into an application", it solves the problem "how to help developer to program a stack machine". It was fitted to a simple, but useful abstraction - stack machine. Same with Lisp, APL, C, etc. In case of the C language the abstraction was PDP-11 ISA ;) Glorified data structures -> PL: array -> APL list (cons) -> LISP stack -> Forth relation -> Prolog Glorified data structures -> DB: relation -> SQL (RDBMS) map -> NoSQL K/V stores hashpointer -> IPFS hashchain -> Blockchain Merkle Patricia Tree -> EVM
- ken 6y ago
- yiyus 6y agoIn my opinion, the perfect programming language would have RTL evaluation like APLs but RPN is a superior input method. If I had some kind of IDE that allowed me to "build" APL expressions (and dfns) using RPN as I built algebraic expressions using my HP calculator, I would be a happy man. Forth LTR feels good with small expressions (and many times, that's all you need), but as soon as you have something complex, stack shuffling makes difficult to keep a mental picture of what the program is doing. I have the same problem with complex tacit expressions, I need to "translate" it. But dfns (or k funcs) are trivial to read.