Six programming languages I’d like to see
buttondown.email
buttondown.email
Ada has design-by-contract as part of the language:
https://learn.adacore.com/courses/intro-to-ada/chapters/cont...
Since Ada is used for safety-critical systems programming you could argue that it is very serious about it.
>> And tool integration! One of the coolest things Eiffel sorta did was use contracts to infer tests. If you have contracts, you can use a fuzzer to get integration tests for free.
How about tools that extend design-by-contract to formal verification?
https://learn.adacore.com/courses/intro-to-spark/chapters/01...
SPARK is limited to a subset of Ada, so it is not without limitations, but it can be very useful depending on what you are trying to do.
Mostly what Ada lacks is not the features but the comunity effect, we saw that when comparing feature parity with C++ and we see that again when comparing feature parity with Rust.
There are a lot of briliant features and tooling in Ada, but unless there is a community effect (or a gigantic industry sponsor e.g. golang) it is difficult to convince people to switch over.
I can't remember who said it so I will paraphrase, the best language/target to program in is whatever your friends/colleagues are using.
Agreed. If there had been more free (gratis) or low-cost Ada compilers at that time Ada would be far less niche than it is today.
There is increased interest in Ada today thanks to Rust. There is also interplay between Rust and Ada/SPARK features with Rust getting some Ada features and SPARK getting some Rust features.
Ferrous Systems is working with AdaCore on the Ferrocene Language Specification to formally document the Rust subset that Ferrocene will use:
https://ferrous-systems.com/ferrocene/
https://ferrous-systems.com/blog/ferrocene-language-specific...
It is exciting to see Rust mature so it can one day be used in safety-critical work.
Don't look a gift horse in the mouth.
The same can be said about Eiffel.
Didn't they? I wasn't around then, so I'm working with what information I can find online. According to Wikipedia it was fully validated in 1995[1], and I'm pretty sure it was always a free compiler based on GCC. I think the dust had settled on the battlefield of the language wars long before Ada 95. It was/is still common for European universities to teach Ada as part of the computer science curriculum. That still hasn't managed to give Ada the industry presence it deserves. In my opinion it's by far the superior language. It's just losing out for human reasons.
> ...gigantic industry sponsor e.g. golang...
It had the biggest industry sponsor at one stage: The US Department of Defense. Back in the late 70s, and early 80s when the DoD was directly sponsoring Ada's development, they had incredibly deep pockets. I'd say this is why Ada is so comprehensive today. They had the money, and motivation to design the language by committee down to the most minor details.
I've read that the hardware required to use an Ada compiler was far more expensive than its competitors as well. I've heard more than one person say that this was a serious barrier to its adoption in the wider industry.
(Lots of formal verification languages are based on contracts, like SPARK, Frama-C, and Dafny. I'm interested in uses for contracts that aren't just formal verification, though!)
Ada 2012 design-by-contract features aren't just for formal verification, they can be used in a general purpose way similar to Eiffel:
https://learn.adacore.com/courses/intro-to-ada/chapters/cont...
Can you elaborate a bit more about the wanted features for a language with semantic relations?
That capability would be very useful. There are many cases where I have had to define serialization and deserialization functions for numerous objects and had to create so much "boilerplate" unit test code like you describe. It made me wish I was using a Lisp with built-in reader and printer functions.
>> being able to say that two data representations are isomorphic under a given transformation, so I can define a function for one transformation and call it on the other.
This strikes me as very Haskell-ish, but could be quite useful to ensure certain properties or invariants.
It's the furthest thing from a "dynamically typed language" but it can probably also check the "math" requirement here too.
[0] https://www.riskdataos.org/html/HelpCenter/Content/CDL/CDL_S...
The “open” alternative is OASIS. Their Open Exposure Data standard [1] is complete and supported by many industry participants. Unfortunately it’s a database based format, rather than a text based DSL, but still betterthan the alternatives.
[1] https://github.com/OasisLMF/OpenDataStandards/tree/master/Op...
What are the consequences of deciding that no Foo's are allowed to be red? Hmm, that's interesting/unintended...
The main difficulties with statically typed languages seem to be both 1) quickly arriving at a workable prototype, and 2) dealing with the consequences of regrettable decisions made early on. Those two being in tension contributes a lot of drama, and not just in analysis paralysis.
https://flang.dev/tutorial/pre_post_conditions https://github.com/tokiwa-software/fuzion
Disclaimer, I work in the Fuzion team.
Maybe that's harder than I can imagine, or it exists and just isn't a very good idea in practice (how would you even do responsive?) so it's not that popular.
VB was a garbage language by modern standards but I always liked that they gave you a visual builder, but didn't try to hide the coding from you too much.
On the web side I bet the right person could do something quite intuitive with CSS Grid though. You could drag out where you wanted various content blocks to appear at different screen sizes and generate a `grid-template-areas` [0] property to match it.
[0]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-templa...
WinForms satisfies my VB6 craving.
This is kind of what WebDev (by PC Soft) does. I worked with it in an enterprise environment. It's nice for internal products, though the code I worked with was old code made by people that didn't have any formal education and not much experience in software engineering.
My favorite part of this was not the GUI, but the deployment part: you click on a few buttons and it just deploys stuff to the server and works. My least favorite part was that sometimes this deployment didn't work and troubleshooting it was long and tedious.
All in all, it wasn't that bad to use, but a big problem is that it's not that well known, so when you look up how to do things, you have the official documentation which isn't great, the forums that are helpful from time to time, or doing it by yourself.
But for network/web service tools, I like that it compiles into a single executable where its internal web server generates the HTML dynamically. It allows me to write small, single focus tools quickly.
It was no Apple's Cassowary, but so isn't HTML/CSS.
It never took off because SproutCore turned into Ember and then died, I think, but not before my company had written numerous things in both SC and Ember...
In principle it worked very differently though; as you said, it was mostly a code generator. Atlas was a port of Cocoa's Interface Builder (which uses state/value serialization as opposed to code generation) to the web.
I've written a few toy apps in it and in my limited exploration it seems to be a joy to work with, once you get used to Pascal's quirks... and I'm not a fan of the ancient MDI workflow it imposes either.
I also learned to program with VB and Lazarus is the closest thing I've found. The WinForms designer in Visual Studio would be the next closest.
Both GTK and Swing have various GUI designers that are similar, but have their own design and use different layout metaphors. If you're looking for a more modern take on what's left of RAD maybe check them out.
That's why it looks so similar.
I still remember the great VB vs Borland Delphi wars of the 90's.
But feel free to correct me if I'm wrong.
I took a cursory look and I don't think it supports Apple silicon out of the box. Considering that Intel Macs are dead end it't not too encouraging.
Emulation works pretty well from what I hear, is the lack of support that big of a deal right now?
There is a quick demo[4] on the site to show how it works.
Full disclosure: I'm a developer on GuidedTrack. Any feedback is appreciated.
[2]: https://mindease.io/
The only reason I would ever use Clojure instead of Racket would be if I needed to work with the JVM ecosystem or the browser via Clojurescript (which are compelling reasons).
Totally agree about a good calculator language.
VB is often scoffed at, and probably to an extend rightfully so.
But those (i.e. VB1 through to VB6) were the ONLY languages that I ever managed to create useful, finished tools and programs in. Maybe it's part psychological, but I needed the approach where I created a neat UI first, got my methods pre-populated for me, and had something tangible to look at early in the process. Then went on to fill it with all with custom code. Yes, it's BASIC, but it was extensible. People I knew wrote OCX and such control elements, and code routines in DLLs in C/C++ and integrated that into VB projects, so the sky was still the limit.
Staring at an empty text document with possibly some header file statements never evoked the same creativity with me that VB did.
p.s. my proudest creation was a Windows 3.1 UI around the MS-DOS packing program "arj", for those who remember. Had I been a better businessman, that might have predated WinZip :)
I developed in an odd Language…LabVIEW…and I get what you’re talking about with first class GUI support and being able to see something each step along the way.
On Error Resume Next anyone?
That said - while VB had an amazing IDE and overall developer experience, the VB language itself had some serious warts.
Your point is spot on.
Wait until someone shows “real” programmers PLC ladder logic and they become aware of just how much critical infrastructure runs in a programming language that was literally designed to allow electricians and mechanical engineers automate real-time safety critical automation controls.
I don't know why people would scoff at BASIC, tons of people make their careers writing Python, which is 100% going to be regarded as the BASIC of 201X-202X.
1. 1 mildly technical, mostly business-domain person, a spreadsheet + auto-clickers
2. 1.5 persons still only mildly technical and mostly business-domain-y, a VB gui and some basic network integration
3. [some time and quite a bit of revenue passes]
4. they hire some java programmers to rewrite it properly in Swing, since the VB versions had literally become impossible to modify without breaking (there were forked versions where you used version A for some feature, version B for another, version C for another - and people had tried to merge them together while keeping the whole thing working, but never managed it).
It's now been, oh, over a decade I suppose, and while I understand that there are currently some efforts underway to port the java applications to an SPA web app, it's more because the owner wants to get rid of java (and only have to hire python devs) than because the apps don't work or are hard to maintain.
My point is that without VB, the company probably wouldn't have existed to even need the Swing rewrite. So while I personally find VB to be quite caustic to my senses, I cannot deny its ability to create business value, especially because it's so approachable only mildly-technical folks.
Have you tried Delphi?
https://en.wikipedia.org/wiki/Delphi_(software)
- my experience was in the 90s, but it has a similar ‘quickly build native Windows UI programs’ feel to it.
Though the language is also showing its age and perhaps isn't for everyone, like how C++ might also be an acquired taste. Some things like talking to RabbitMQ, Redis, gRPC, GraphQL or MongoDB (just as examples) might be a bit more difficult than in other languages that get more love.
Game tooling has also moved to cross platform these days with popularity of MacOS for content creators and iOS as a target market requires MacOS for development tools.
Mac platform is about 15% of world desktop market, hope they can manage all requests from game studios all around the globe.
I fondly remember trying to explain why Emacs doesn't have a green run/build button :-)
Vb was easy in a way *nix never was!
>Planet Source Code
So many good memories of browsing that auto-scrolling list of new projects, downloading and trying something different and learning by seeing new code.
My impression is VB is a language sucks but VB the entire package (forms, form editor, IDE, etc) was pretty awesome.
So the arguably a similar IDE with a better language would be a huge win.
WinForms absolutely captured most of the same feel of VB6 from strictly the perspective of the tooling. I think it took a while to really catch on because, being a from-scratch rewrite, it took a while to gain complete feature parity, while also lacking the subcomponent market that a lot of VB6 projects had grown to rely on.
But then, GUI requirements also evolved. HighDPI displays, internationalization, accessibility, bigger and bigger projects needing better organizational methods. You can solve most of these issues in WinForms by being super fastidious about componentization, but it's not the happy path of just double-click-on-the-form-designer.
All of the XAML-based GUI systems that Microsoft developed since then have tried to invert that issue. They wanted to start people off by being considerate of componentization. Unfortunately, it came at the sacrifice of the usability of the tools.
I had an entire career built on developing back end tooling in VB for businesses, some of which (.. 25 years later?) are still doing their jobs. It was sometimes painful but it really did set a bar for quick productivity. Fond memories of those days!
Myself and a lot of kids probably grew up on VB. I was one of those annoying kids writing AOL 3.0 'progs.' I don't think I've ever had as much fun coding as those days, but that's probably due to age and community moreso than VB's greatness.
Visual Go, Visual Rust, Visual Nim and Visual Crystal, where are you?
One of the truely great things about the drag and drop form builder was being able to sit with a user and go through requirements with them, to wire it all up later.
"Ok, so when you type in the customers details, we should have a button to save them into the database. Will we put it here?"
And this all still works today in VS 2022.
It already offers plugin controls that work with the builder or just code.
Can deliver native local apps, websites, webapps, iOS and Android apps, etc.
Database controls like in VB and Delphi - and much more to come.
It is programmed in and with Common Lisp, however you can easily program events in JavaScript and Python coming soon too.
What happened was that I lost interest in creating that kind of thing. And the business decided that such programs have to go through a formal approval and release process, so it left me with no advantage over letting the software department maintain that stuff at considerably greater expense. Today, I'm willing to burden my users with stuff that requires a bit more care and feeding on their part, such as plain Python scripts. Also, VB turned into VB-dot-net.
I'm equally creative in C, but on the embedded side. Something about working within severe limitations. I'm reminded of a quote from Richard Feynman: “The game I play is a very interesting one, it’s imagination in a tight straitjacket.”
The weirdest thing (I have ever seen in software): Once VB.net hit, all VB devs quit. VB.net was a totally different language. I guess we all moved on.
Delphi and friends[1] is still out there. There's also Lazarus[2] if you don't want to fork off a few grands.
[1] https://www.embarcadero.com/products [2] https://www.lazarus-ide.org/
JavaFX has SceneBuilder[2] which also fit the description but for some reason, it never caught on. Gluon seems to have that work not only on desktop, but also on mobile.
[1] https://docs.flutter.dev/development/tools/devtools/overview
Still, there's a lot of things that would be more useful with such a language. In-memory highly-correct cache invalidation would become trivial code to write. In fact I think the cache would actually update itself live. Out-of-memory cache invalidation might be pretty easy. Certain auditing things would be easy. UIs would probably take some work to get right but would be interesting, at the very least. Game programming would also be interesting; a lot of game patterns would be incorporated into the language at that point.
Probably need to be lazy; I suspect proactively recalculating everything all the time would be a bad idea. Haskell has pushed lazy programming a long way, but "re-thunkifying" a previously calculated cell would be a new frontier.
Come to think of it, while I think the performance could be improved and you'd want to lift up to a full language eventually, I think a good Haskell programmer could bash together a prototype of this in a few days and start playing with it. It's going to need a lot of playing with before someone casts it into concrete as a language specification and corresponding compiler and runtime.
My language turns out to be very fun to write UIs and games in, so I'm glad you honed in on those two examples. Actually one way to view it is that it's a programming language with a game engine as a runtime. But robotics is the primary application I'm targeting.
In fact I had to choose between lazy and eager evaluation, and I've chosen eager because I want latency guarantees. With a lazy evaluation scheme, I was unsatisfied with the windup that would occur in some situations that would totally blow performance. And we don't have to recalculate everything all the time; we only have to recalculate the paths that have an input change. This may lead to recalculating everything, but most of the time we only have to focus on the execution path that is "dirtied" by the updated input.
Anyway if you want to test drive such a language as you're imagining, send me an email and I'll give you a tour/demo. The language isn't really user-friendly yet so there are some pointy edges that make it unusable to new users at this time (which is the main reason I don't want more attention on it until that is resolved.)
https://github.com/kennytilton/cells
and he has slides from a talk
https://github.com/kennytilton/cells/blob/main/Lisp-NYC-2018...
to give context.
Reactivity in Jupyter would probably have to be provided by the kernel, not by the Lab frontend.
https://powerapps.microsoft.com/en-us/blog/power-fx-open-sou...
https://github.com/microsoft/power-fx-host-samples/tree/main...
$: b = a + 1
Since it's a compiler, it knows what inputs were used in that statement, and what outputs were mutated. The statement is re-run every time its inputs change.This is then used to make a web development environment where "react to input changing" is much more natural than with e.g. React.
#!&/@l
It has the same "everything is a list" problem - it's really verbose at handling strings, for example, and last I checked its date-time handling was not only verbose but also [flat-out wrong](https://mathematica.stackexchange.com/q/239480/30771). But it does support the dynamism mentioned immediately below, if you use `SetDelayed` (`:=`) rather than `Set` (`=`).To be clear, I like PHP. It actually has many attributes that make it almost ideal as a Web development language, most notably:
1. Pretty much everything is request-scoped. This makes it a lot harder to leak resources when everything is torn down;
2. A stateless functional core. This avoids a lot of class loading that has dogged Java (as one example);
3. No ability to start threads. This is actually a positive. Most application code should avoid creating threads like the plague.
But PHP comes with a lot historical cruft. It's type system is also primitive (Hack is a better example of this).
Where I think this could really shine is in data analysis (ie the numpy/scipy realm).
As for the type system, haven't worked Hack but I absolutely love the gradual typing experience that PHP offers. Yeah, we had some things that could not be expressed but they are slowly being added, again we have finally union types!
I would even say PHP might be the only mainstream language that offers a first class gradual typing experience.
In Python your type hints are a lie as they are not enforced at all and different linter will give you different results and there is no standard.
In JS, you have to use a whole other languages that compiles down to it, slowing you down with an extra compile step.
Meanwhile PHP just works. Just use PHPstan for linting but even if you don't you get at least runtime checks.
For other languages, Ruby for example feels a lot more stable. I'd expect that tcl, perl and most lisps are as well. But in fact I am still searching alternatives for the times I don't want to use ruby.
I don't know if it's changed recently but that's something I really appreciated when I wrote PHP: it was unabashedly singular in it's purpose as a web scripting language. The source article talked about VB6 as being a language where the GUI was a first class thing; for PHP the only focus was on making applications around web requests. No useless bloat while trying to be a general purpose shell scripting language; no delusions of grandeur of trying to be an enterprise business logic tier language... it did it's one task, did it well, and left other languages to other tasks. I think we would be better served to have languages will small standard libraries focuses on specific tasks rather than gigantic one-language-to-do-everything but about which nobody could possibly know everything (ahem C# ahem).
I write PHP every day (just took a break from that to be here) and the request scoped content is both a nice thing and a pain in the ass some times. It's great that each request is on it's own - really handy for cleanup like you mentioned. There are some thing I want to be shared though, like a DB connection pool, a caching layer (one layer below my Redis layer), and clients for various other services.
Not the end of the world, but an example is AWS Secrets Manager libraries for Python support secrets caching, but they can't offer that in PHP since we won't be able to share the objects. You can use the file system, but that comes with its own hosts of quirks.
That said, PHP really is a fine language. I'm personally not a fan of the use of truthy/falsy values, but they've really dove head first into solid type support. Lot's of good progress has been made with it.
As for why AWS doesn't use it (if that's your question), I assume they didn't want to deal with the need for a system dependency also. That's something that is kind of a pain to me with PHP as well. Some PECL, some Composer makes mentally tracking and managing deps a bit trickier.
You also want to look at Dafny for a contract-based language: https://github.com/dafny-lang/dafny
Since it has verification support it also covers the second point about semantic relations.
…have to poke around a bit methinks.
In Shen, the contract rules applied on each function are themselves a Turing complete language::
https://thestrangeloop.com/2014/shen-a-sufficiently-advanced...
"static type checking based on sequent calculus"
"one of the most powerful systems for typing in functional programming"
Shein never became a serious language. It's highest point was when @deech made a talk about it and it also promoted their klambda but it had constant problems on every single aspect of the system and the design, from code size expanded as macros to unusable APIs due inconsistent design of libraries and features the author collected from everywhere. I even bought the book and felt deceived after it's unsuitability for anything other than academic examples on how to implement itself.
> window2 is an optimized version of window1 and should have the same outputs for every input. I should be able to encode that in the language, and have the tooling generate checks showing the two are the same, and also run benchmarks testing if the optimized version actually is faster.
That should be possible with Joy, it's certainly something I want to explore. The interesting semantic relationships are those that let the machine automatically deduce optimizations
> I also like the idea of modifying function definitions at runtime. I have these visions/nightmares of programs that take other programs as input and then let me run experiments on how the program behaves under certain changes to the source code. I want to write metaprograms dammit
Lotta metaprogramming in Joy. Many functions work by building new functions and running them, it's a natural idiom in Joy.
- - - -
> A language designed around having first-class GUI support
Red? ( https://www.red-lang.org/ )
> Visual Interface Dialect ... is a dialect of Red, providing the simplest possible way to specify graphic components with their properties, layouts and even event handlers. VID code is compiled at runtime to a tree of faces suitable for displaying.
https://github.com/red/docs/blob/master/en/gui.adoc
> You can’t work with strings, json, sets, or hash maps very well, date manipulation is terrible, you can barely do combinatorics problems, etc etc etc. I want a language that’s terse for everything.
That also sounds like Red.
If Alan Kay had got microprocessor companies to steal the Xerox microcode design like they got Apple to steal the GUI design, then the genius compiler engineers optimized the the heck out of it all.
I can only shudder at what the supercomputer in my pocket would be capable of.
Lisps are not the God-languages.
Lisp ain't gonna help with any of that.
Technically, the runtime is the easy part (relatively speaking). Modelling an array of swimlanes on a plain-text 2D page is the real challenge here IMO.
But a visual language either requires specialist tooling which I think deters a large number of people, or if implemented in plain text, degenerates into ASCII art, which is very hard to manipulate in a simple text editor (believe me, I've tried!)
A structured non-visual language is also possible, but that turns fairly quickly into a functional language which per se is not bad, but is not helpful when trying to present the overall flow of data around the network. You still have to jump around the file from function to function to try and understand what is going on.
There must be a middle ground out there somewhere. Simple plain text presentation of multiple streams of processing.
Raku, previously known as Perl6, has this[1].
sub MAIN(Int $a, Int $b where 10 < $a < $b > 20) { say "OK: $a $b"; }
You can also pull out the "Where" clause to ouside the function and make it define a new type.
Raku is a very awesome language in general, for more reasons than one.
[1] https://andrewshitov.com/2020/08/14/the-pearls-of-raku-issue...
The same machinery that runs "<" or ">" at runtime would just as well run coprime and prime.
In retrospective it is funny how everybody implicitly assumes that the next big thing will be yet another programming language. And I am not talking about no-code or AI code synthesis.
Lisp is a dynamically typed impure functional language. Programs are nested lists. Its interpreter runs by calling eval and apply, which call each other. After compilation, code runs on a machine with a program counter and stack.
I don't see much similarity myself, and I wrote FMJ and know Lisp well.
The actual sequential thing is consequence of states s0, s1, etc and the only deviation form sequence would be another timeline or state that did not produce.
My point is just because you use a sequence-based input method (a programming language) doesn't mean you can't express structured data.
For example jq[1] does a decent job of expressing queries and transformations on JSON (JSON data are trees rather than arbitrary graphs). But trees are a very important type of graph, and I think a language with first-class support for trees would be in a better position to handle arbitrary graphs than a typical programming language.
Especially with reactive programming as an ask there, I would recommend Julia with Pluto.jl (Pluto is a reactive notebook).
> A really dynamically-typed language
Julia ;) It is really dynamic, has meta-programming (macros + staged functions), solid semantics around eval/invokelatest that still allow for optimizations and you can add types at runtime (not modify them though).
you can create comments above methods that act as tests
It's true that Racket unit tests are an optional module within the standard library, but the command line tools and package system work directly with it. You can place unit tests right alongside the regular code but within a specially-named "test" submodule, so the unit test code doesn't run at runtime by default, except in certain contexts (package installation, "raco test" command, or running the file from within the Racket IDE).
It would also be nice to have system-level contracts. Like, say, "every item in list X should have an entry in dictionary Y". Or "no button should be located outside the visible viewport". These are the sorts of things that people procedurally unit test, but expressed in a declarative way you can imagine all sorts of tooling.
This could theoretically be added to other languages with libraries (with varying elegance depending on the language), but a real first class language would be carefully designed so that everything is serializable and deserializable with excellent performance. Things that fundamentally are state like network connections would also have to be carefully handled in some way where their essence was persisted such that the program could restore them and rebuild their state.
This would pretty much give you an ORM without the impedance mismatch and would eliminate a TON of "CRUD" code and boilerplate.
It's defunct now, but it was indeed a Turing-complete SQL (but actually relational) with Prolog-like syntax and set semantics. We supported persisting data, and indeed you could think of it as programming within a database. Even though it's not worked on anymore, the last version in the repo worked pretty well IMO. I built a Spotify clone, and even a robot in the language. If you're interested in these ideas, you should give it a shot! Hopefully someone will pick up these ideas and run with them even further.
It's a pretty mind-bending experience to program this way, and I promise you'll have a new perspective on programming as a practice once you grok it (that was common feedback from our users).
That's a pretty weird way to do math, honestly. Shouldn't you figure out what equation you need and then just type it? If you're off by one or whatever, adjust it then, you're still only typing it twice.
I found that for much of my code it really separated the “where to next” from the “what to do”. And I became acutely aware of how many of the statements in other languages are more about “where does the code go next” and less about getting stuff down.
Prolog does, but more intriguingly, so does Nix!
But it's not quite the same thing, because all "boolean" operators in BASICs of old were actually bitwise! It worked in practice because the convention was to represent true as all-bits-set (i.e. -1 in two's complement). No short-circuit evaluation, of course - but back then, even languages that had dedicated boolean data types, like Pascal, didn't do it either.
from math import *
prod(map(factorial, l))
which isn't much longer than his J code especially if you count the number of tokens rather than the number of characters as the J code uses ridiculously terse names.I bet that changes eventually when we reinvent personal computing again (currently we are reinventing mainframes).
I've been working on an extremely dynamic programming language for a while. Ricing away on the syntax to make it as flexible as possible, whilst maintaining readability.
One of the things that already works is some insane metaprogramming. It doesn't really have functions. It has callable lists of things. Which means you can modify them at runtime (still working on the names for the functions for doing that).
It is stack-based, so it's a little quirky, but as a taste of some very simple meta-programming:
block
varname:
add! 1 $ $varname
: $varname
end
inc-env:
a: 1
inc-env! a
Bare-words are a symbol-type. So they only resolve from the environment when you ask for it with the $ instruction, which is how the above works. A little tedious, but does enable all kinds of dynamism.Once you know this and the difference between definition context and bodies (which is simple) there isn't much to add. The top-level works mostly like letrec*. Internal definitions work like letrec* Libraries work like letrec*
PostScript is one of the very few stack-based languages that is used anywhere, and it's mostly used in anger. Forth has a bit of a following, but the syntax isn't as regular as Lisp, which makes metaprogramming a tad annoying at times. So I was curious if I could use the f-expr to change both of those. Thus far... I think it's a workable concept.
Not really. Not committing to anything publicly has let me feel more free to tear down and start from scratch an embarrassing number of times, and experiment a bit more. Makes it easier not to get over-invested in any one technique.
I have written a little bit, as I've slowly changed my approach. But it's haphazard. Not a whole heap. You can, though, see a few of the previous versions, that do "work":
+ 2 years ago: https://git.sr.ht/~shakna/esom
+ 3 months later: https://git.sr.ht/~shakna/stackly
+ 6 months ago: https://git.sr.ht/~shakna/james_scriptlang
It's still evolving. You can see where some things have stuck, and others have been tossed by the wayside. The current incarnation isn't public at all, yet.
If I ever get satisfied that I've got the right approach, I'll probably do a big write-up, then.
> My next question was, why on earth call it a functional language? Why not just base everything on FEXPRs and force evaluation on the receiving side when needed? I could never get a good answer, but the question was very helpful when it came time to invent Smalltalk, because this started a line of thought that said "take the hardest and most profound thing you need to do, make it great, and then build every easier thing out of it". That was the promise of LISP and the lure of lambda—needed was a better "hardest and most profound" thing. Objects should be it.
You can see the basic idea for the Vau calculus in that quote. Shutt (RIP)[1] later elaborated the theory and proved they were not "trivial" and anathema to compilation [2]. It's great to see new interpretations and uses of the fexpr!
[0] http://worrydream.com/EarlyHistoryOfSmalltalk/
[1] https://en.wikinews.org/wiki/Wikinews_mourns_loss_of_volunte...
You can literally extract the body of a function as a list of "call" objects (which are themselves just dressed-up lists of symbols), inject/delete/modify individual statements, and then re-cast your new list to a new function object. Or you can construct new functions from scratch this way.
I've written utilities before that will inline specific function calls within the body of another function, or that implement function composition by constructing a new function from scratch.
I don't know why the original devs thought this was necessary or even desirable in a statistics package, but it turns out to be a lot of fun to program with. It has also made possible a wide variety of clever and elegant custom syntaxes, such as a pipe infix operator implemented as a 3rd-party library without any custom language extensions [0]. The pipe infix operator got so popular that it was eventually made part of the language core syntax in version 4.1 [1].
Arguments sent as `[blocks]` are always unevaluated but you can also explictly set a function argument to not be evaluated...
f: func ['a] [
print ["you gave me: " a]
print ["and this is what it evaluates to:" get a]
]
val: "hi!"
f val
Outputs: you gave me: val
and this is what it evaluates to: hi!
And the function body is mutable... f: func [a] [
print a
]
f 10 ;; => 10
append second :f [* 2]
f 10 ;; => 20Dependent types and things like that are probably great. Being able to prove correctness is great. But I would settle for a way to declaratively express invariants and then let the language for the most part take care of inserting checks (in debug or using a special mode perhaps, or all the time) and generating tests/property tests. Why isn’t this more of a thing?
Because that's a half-assed way of using and leveraging a good type system? DBC always strikes me as a "three blind men and a type system worth using" parable.
A type that proves that all values that inhabit it are sorted would also be nice. But if either the language doesn’t support dependent types or it is too difficult to prove then a contract could be used instead (again: not as a replacement).
So to my mind (repeating idiom) it can work paralell to the type system. What’s not to like (honest question :))? It doesn’t have to be intrusive, as far as I can see.
This is really easy in a dependently typed language. If something is hard to prove by construction you can do
sort: List -> List
which sorts a list without proving it to be sorted, and then write a function isSorted: List -> Maybe SortedList
then just get your safe sort function safeSort: List -> SortedList
safeSort l = case sort l of { Nothing -> panic; Just x -> x }
Of course, you don't even need dependent typing to do this. If SortedList is a new nominal type and you trust your issorted function, everything works out.I have frequently found myself out of my depth when trying to write what I thought should be straightforward dependently-typed code. I got the hang of it after a lot of practice (as well as a lot of reading, note-taking, and outside help). But now you're asking programmers to learn an entirely new set of skills on top of everything else they're expected to know.
I love the idea of dependent types, and I've had a lot of fun messing around with Idris 2, but I think dependently-typed languages have a lot of work to do in order to bridge the ergonomics gap.
I'm not convinced that, for garden-variety software development, dependent types are substantially safer than extensive use of contracts and property-based testing.
Ah, I think I see what you mean. Yes, that's also possible, but you are losing the full safety of dependent types, and are just back to contracts!
v M ! v R *
Where the v may be capitalised if you like and the spaces are the way the commands are written but aren’t typed. That decomposes into some easy mnemonics: Vector Map factorial, Vector Reduce multiplication.It has a bunch of mathematical features, a quick interface for plotting simple graphs (with gnuplot), some symbolic algebra, and it sort-of has the reactive feature too. (I think there’s also a mode for using it in files).
Date handling is ok but simple (a date/time is internally represented as a Julian day so if you add 1 to a date/time you get the next day; times go into the fractional part. Leap seconds / time zones aren’t handled. There is an option to configure when your calendar switched from Julian to Gregorian.
It’s usually fast enough for what I use it for but it can be limited by performance.
Edit: I tried using J and the install was pretty large iirc and the whole language is just too big and complicated. I know you can do cool stuff with it, but it just seemed to me that the cost was too high relative to benefit. Your mileage may vary.
input = 1
out1: input + 1
#out1 is now 2
input = 4
#out1 is now 5
out2: out1.replace(+, -)
#out2 is now 3
# let's pull an APL
input = 4 2
#out1 is 5 3
#out2 is 3 1
The reactive programming idea a la Excel but text-based looks really neat. I'd love to play around with that kind of thing.https://docs.microsoft.com/en-us/power-platform/power-fx/ove...
That's like saying "There will never be bugs".
There will be bugs.
And when you come across one and you can change a variable and have another variable affected in some other part of your program and you have no idea how these two variables are connected, you are going to have a nightmare of a time debugging.
> you have no idea how these two variables are connected
Simply traverse the reactive graph to reveal how/if two variables affect each other.
Cycles and dynamically changing bindings are still problems, but they can be tackled.
Lua is based around tables, which, aren’t quite graphs but seem relatively close enough. What is a graph if not a collection of points associated with their edges?
As far as semantic function relations, I could swear Ada has something like this, but it’s been more than a decade since I’ve touched any.
Not ambitious enough. We already have dependent type systems and what I will call “property based types” since I forget the proper name e.g. https://ucsd-progsys.github.io/liquidhaskell-blog/.
The compiler can check anything from silly out of bounds conditions to more complex assertions.
Even without that, a good type system will allow you to alias types but have a constructor do a check. Once you use the Percentage0_100 type you know that it must be in that range, and the method doesn’t need to check it again.
In think Haskell is “too much” for a lot of teams, but sprinkling in some compile time assertions and making that ergonomic with linting and so on would be a boon on par with async/await.
“Unit test?” no need, I have a proof!
Contracts? how they're different or less verbose than plain asserts? what they do better?
"reactive programming"? if remove that strange code editing "replace", just a chain of definitions instead of variables in, say, ruby, gives you basically the same effect.
etc.
What I'd love to see is a language with a first class grammars to replace many uses of regexes or badly written DSL's, like what Perl6 tried to do.
and, somewhat related (both are using backtracking), adoption of some of the ideas of https://en.wikipedia.org/wiki/Icon_(programming_language), not on a whole language level, but in some scoped generator context would be nice for some tasks I had to do.
Regarding first-class grammars you have to understand that it basically prohibits any other tool to parse your language. This means everyone has to fully implement the language to create any kind of small helper tool. In turn, your language might easily fall into the "exotic" camp (like, e.g., TeX - this language effectively has first-class grammars, albeit at a low level).
There are a few more variations of that in the Kotlin standard library and you can write your own contracts as well. There's just not a whole lot you can do with it other than stuff like this. But it's useful.
The major differences are that most (all?) dependently typed languages are functional and require the programmer to prove the correctness of the contract in (an extension of) the language itself, while the others typically use special annotations in normal Ada/C/a generic ALGOLish language and dump the proof onto external tools like SMT solvers, all resulting in a more 'normal' programming experience.
The longer I see things like mypy and typescript evolve, I’m actually really glad that people have been focused on gradually typing dynamic languages. As far as I can tell, really useful contracts (or really flexible types) are super burdensome in the most general cases (e.g. `refl` brain twisters in dependent types), but still insanely useful in frequent cases. It reminds me of what people say about static typing’s benefits and burdens.
So I’m hoping to see the gradual typing equivalent for contracts and verification. Start with usefulness and add a spectrum of optional safety that the programmer can ignore or use as they see fit. Personally, at least, that would be my ideal scenario.
Recently I've been tinkering with an indie Clojure-like Lisp called Janet. It implements Parsing Expression Grammars as a core library module: https://janet-lang.org/docs/peg.html
The use-case was to abstract away having to manually figure out where to put caches and how to invalidate them on front-end servers. Rather, have the runtime figure out how to cache content and page fragments when e.g. rendering the Facebook timeline. However, it was too difficult to bridge the gap to the existing Hack codebase, iirc in particular to the entity system used. There were also a lot of headaches trying to figure out how to power the underlying cache invalidation system.
https://www.youtube.com/watch?v=AGkSHE15BSs
https://web.archive.org/web/20200219222902/http://skiplang.c...
The author I think means something slightly different though, closer to prologue where you define facts and then ask the runtime to make an inference about those facts.
If you write tests now, the extra notations SPARK introduce aren't much more code than you're already writing, and really it's just entering into the code what you (hopefully) have in your head or on paper elsewhere.
Your function only works on arrays of a certain length? Rip out the test-and-return-error code. Skip asserts (that get removed if you optimize). Put the check in the contract and the code won't compile unless the array is appropriate---which might involve a test at a higher level, where the error is easier to handle---and you get zero run-time cost.
Xerox' original XRCE (Research Centre Europe) pages are gone, but other sites offer a glimpse, and FOMA is an open source implementation of the same language:
[1] https://sites.google.com/a/utcompling.com/icl-f11/home/xfst-...
There is recent research in this area.
The difference to asserts is that they express a property over to points in the execution of a program, whereas an assert only states a property of one point in the execution in the program. Practically, that means that you can refer to the state before some code in addition to the state after in the post-condition of that code.
Then there's just a plain old notNull() static method, which will trigger.
How do you turn asserts into generative tests, or assign blame? Clojure's spec has support the former (https://clojure.org/guides/spec#_generators), racket's contracts have support for the latter (https://www2.ccs.neu.edu/racket/pubs/popl11-dfff.pdf). Also, many popular languages have a pretty broken assert statement (C, C++, python come to mind) which conflates optimization levels or/debugging with assertion support. Rust gets this right.
> What I'd love to see is a language with a first class grammars to replace many uses of regexes or badly written DSL's, like what Perl6 tried to do.
Lua sort of does this with LPeg. There's also https://rosie-lang.org/, which is more special-purpose.
I have a bunch of Lua modules based around LPeg: https://github.com/spc476/LPeg-Parsers
Classes ARE functions. Conceptually, they are closures with some automatically generated features and language semantics.
https://www.youtube.com/watch?v=mrY6xrWp3Gs
Classical inheritance is BAD and you wouldn't want that kind of relationship for functions. Ofc, what the article suggests is basically assertions - why execute code once, when you can do it twice!?
Modern languages should have function signatures. After I write tests (a full testing framework should also be native to a language), being able to get a function signature which ensures a pairing with a specific set of tests would be great. No more side effects added in without breaking tests, ensuring you would have to make a test change, even if it's introducing some new side effect that doesn't break an existing test.
Why not parser combinators as a library? The language has to be sufficiently advanced to allow that, but many are these days. E.g. F# has FParsec.
input = 1
out1: input + 1
#out1 is now 2
input = 4
#out1 is now 5
out2: out1.replace(+, -)
#out2 is now 3
# let's pull an APL
input = 4 2
#out1 is 5 3
#out2 is 3 1
Not quite as sleek syntax, but in APL with my Lazy library[1] input ← 1
]lazy out1 ← input + 1
out1
2
input ← 4
out1
5
⎕FX'out1' '\+'⎕R'out2' '-'⎕NR'out1'
out2
3
input ← 4 2
out1
5 3
out2
3 1
[1] https://github.com/abrudz/LazyCopyright would be handled using a block chain so every commit's author would be publicly visible to users of the library.
The "source code" would be stored as a call-flow graph and perhaps nodes would have different permissions to sandbox the effect of untrusted contributors changes.
The type-system and forced spec/implementation split both work well to catch errors; you can go further with SPARK [proving] and using Pre- and Post-conditions, type-invariants.
I think you might not want a blockchain: what you need is a merkle tree, which is basically what backs both git and blockchain
The author says:
> Give me a language where key-value maps are emulated with directed bipartite graphs
So this means you can't define graphs using key-value dictionaries (like Smalltalk or Javascript with their objects primitives). So how exactly are these graphs defined? RDF format?
Something I've found while trying to design languages is that the hardest part is running into contradictions and circular logic. And I feel this "everything is a graph" idea will very quickly run into this issue.
With "everything is a graph", all your operators would expect to consume and produce graphs. So you'd have operators for parent/sibling relationships, operators for various kinds of traversals, extracting graph shape information to build higher-level operators like subgraph isomorphism (or maybe that would be a built-in operator).
If I was designing an "APL for graphs" I would probably take a lot of inspiration from NetworkX[1]. Especially: generators for various graph types, the ability to read dicts/lists as graph data, and a huge suite of graph-related functions.
But I would also want dedicated notation for the most common/composable operations like APL. I particularly like how Jq[2] "functions" are inherently combinators, and Jq has some nice semantics for mapping and filtering operations on trees, but I don't really like its syntax that much.
[1]: https://networkx.org/documentation/stable/tutorial.html
Nevertheless, Lisp is still a very useful primitive for understanding computation, because the means of combination of these primitives are all themselves represented with Lisps. That makes for a very succinct definition for the rules that define computation, because there are fewer special cases to handle. Likewise, it makes it easy to write program-manipulating-programs, because there are fewer special cases to handle.
In theory a graph-based language could have similar benefits. Most compilers already represent programs as graphs internally: there are call graphs, control flow graphs, data flow graphs, type graphs, etc. You could imagine a language that tries to make graph construction & manipulation very succinct, and then see how far it gets you. Sure, at some point you have to implement on real hardware, but you can hide the actual implementation, just like the sophisticated compiler techniques used to transform lists into efficient machine code are hidden from a Lisp programmer who just wants to write some macros.
Actually, the universal 'cons' cell data type of LISP (which is used to build lists) allows to represent graphs. Take, for example, Common Lisp. There are read-macros which make this possible: The expression #1=(hello . #1#) builds a circular list that only contains the symbol "hello" [1]. This example can be extended to build graphs.
[1]: https://letoverlambda.com/index.cl/guest/chap3.html#sec_5
Some languages though have contracts as a library, but that library uses tools of the language, to actually change the language. Languages with capable macro systems! Just because something is a library, that does not mean, that it will not integrate into the language, even beyond a library function level. In language with a capable macro system, one can create new keywords and forms, which are just as much part of the language, as predefined things. It allows to create ones "affordances". With all the interest in language features, I am surprised, that this was overlooked.
The post inspired me to try myself at creating a macro in Scheme / GNU Guile, which implements the "requires" and "ensures" idea, although evaluating at runtime: https://notabug.org/ZelphirKaltstahl/guile-examples/src/d749...
The withdraw example would look something like
impl Account {
#[requires(amount <= self.balance)]
#[ensures(self.balance >= 0)]
pub fn withdraw(&mut self, amount: uint) { ... }
}
and Prusti has a good story for going from this to larger proofs.I can imagine it being Materialize who build this first but in my heart of hearts I’d love it not to be SQL.
It would probably make more sense than HCL or Pulumi.
Agents based language are close in theory but they are really targeted at specific simulation and not at explaining what went wrong.
It would also make it easier to do partial application and resumption of it. And probably make constraints for security easier.
Probably make composition of infra level work easier too.
I'm glad to see there's someone else out there who think's it's useful.
CL-USER> (defvar i 1)
I
CL-USER> (declaim (type (integer 1 10) i))
(I)
CL-USER> i
1
CL-USER> (setf i 8)
8
CL-USER> i
8
CL-USER> (setf i (1+ i))
9
CL-USER> (setf i (1+ i))
10
CL-USER> (setf i (1+ i))
; Evaluation aborted on #<TYPE-ERROR expected-type: (INTEGER 1 10) datum: 11>.
CL-USER> i
10 #pragma strict_types
void main()
{
int(1..10) i = 3;
i += 7;
i += 1;
write("%O\n", i);
i = 11;
}
output: typetest.pike:6: Warning: An expression of type int cannot be assigned to a variable of type int(1..10).
typetest.pike:8:Bad type in assignment.
typetest.pike:8:Expected: int(1..10).
typetest.pike:8:Got : int(11..11).
Pike: Failed to compile script.Edit: I've posted this same comment in multiple places in this conversation to get feedback from specific commenters, not as spam (it's a old personal project)
In other words, a step-by-step learning process from simple to hard, maybe 2-4 levels, and you never have to throw away what you already learned and start over, when going to the next step.
(I know that's not quite what you're saying -- it sounds like you're asking for a "Rust--", which is Rust with some complicated stuff turned off. But it's a start.)
To slightly clarify my earlier comment: I am learning rust and plan to use it, but in the long run it seems it could save time for the world overall, if there were something to recommend to others, say, members of a team who want or need something easier, but is easily transitioned to full rust, with as much shared knowledge between the two as possible.
* There is just a few primitive node types (Class, Method, Attribute, Relationship, GUI Bucket) with the rest of the system being derived off of that.
* Underneath is a replaceable layer of java (+js/html for UI).
* Still not sure if it's quite front or back end code, as it contains business logic, GUI info, and largely runs on the server.
* Back end improvements happen automatically and system wide. The limiting nature of the graph ensures minimal regressions.
* Most of the SKU product code is contained within this graph, making for definable relationships between any part of the code.
* Internal languages mean lots of internal tools that enable better management of the graph.
I really like the idea of zx, but still doesn't look clean enough to me.
> A serious take on a contract-based language
As the article itself notes Clojure does support contracts in the language and with libraries. But there has been a ton of research about that, e.g. JML [1].
> A language with semantic relations
They can be expressed in contracts (e.g. Clojure) or with property-based test frameworks (e.g. Haskell, Clojure, and many others nowayday).
> Everything is a Graph
See graph rewriting, e.g. [2]. That was just my first google hit with the proper search term.
> A better calculator language
That idea looks to me like automatic transformation from offline to online algorithms [3]. I am not aware of any compilers being able to do that. But dataflow graphs can be used to design such systems. A list of such languages or libraries (e.g. for Clojure) can be found in this Stackoverflow article [4]
> A really dynamically-typed language
As some other answers here already mentioned modern static type systems are able to express, new types at runtime, e.g. with Scala's path dependent types. Again Clojure has an interesting entry here: clojure.spec [5], a runtime represented specification language, which can be used together with contracts or to formulate proeprty-based tests, or anything else you would like to do with it.
Btw, I've only toyed with Clojure so far and I used to be an avid proponent of Haskell/ML-style static type systems.
[1]: https://www.cs.ucf.edu/~leavens/JML/index.shtml
[2]: https://link.springer.com/chapter/10.1007/978-3-642-32211-2_...
[3]: https://en.wikipedia.org/wiki/Online_algorithm
[4]: https://stackoverflow.com/questions/461796/dataflow-programm...
Frink (https://frinklang.org/) has been around for ages, and is rooted in physical unit conversions
Calca (http://calca.io/) has come up a handful of times. It looks pretty reasonable
R, if that's your flavor
Anything with a REPL. Though the OP suggests these are cumbersome, I'd counter argue that anything you know well is usually more efficient than learning something new.
A very long list of commercial tools: Matlab, Mathematica, WolframAlpha, STS, SAS, etc
Spending the last 6 years writing Clojure has been great. That said, the parens don’t add positively to the experience. They feel like semicolons in C - “the compiler is too dumb to understand this so I have to help it.”
Fair to mention dart (flutter) in VSCode has a refactoring option which removes, adds and modifies all widgets but it falls short in comparison to lisp.
I have only wrote LISP code during uni and on pet projects and I always feel like the parentheses are making things easier to visually process. The AST is explicit and basically just before my eyes, and it looks nice because of the functional style.
This is a cool idea especially around a formal structure to express relationships between parts of your code. As to the example in the article on this, it seems property based testing is a decent way to achieve something like this with existing languages.
A simple example of a property based test for a `const add = (a, b) => a + b` function would be that the result of the invocation is always larger than the arguments IE
expect(add(a, b)).toBeGreaterThan(a);
expect(add(a, b)).toBeGreaterThan(b);
And then you can randomly generate or fuzz the values for a and b but the test should always passMe too. But there is something nice on Linux called GAMBAS: http://gambas.sourceforge.net/en/main.html
In other words, a step-by-step developer growth process from simple to hard, maybe 2-4 levels, and you never have to throw away what you already learned and start over, when going to the next step.
You can also do explicit memory management, which of course takes more programmer effort.
It turns out most programs wind up using a mix of the two, as GC is better for some things, and explicit is better for others.
I will keep D more in mind though...is it on openbsd? (Edit: I see it is probably at least there via gcc, at least.)
Also the D in gcc is full fat D, no "at least" required.
And it's fast, enjoyable and productive
And for the first-class GUI support, in its own way too, but also Swift in XCode is very very good.
And it's because I haven't thought yet about how to do static type checking with such a feature.
I haven't got any time to work on it in the past few weeks, and I'm the only dev (would really love some help). So, it will be ready when it will be ready :P
I've been playing around with it and find it can really simplify a lot of code.
normal assignment:
var : expression
view:
var :: expression
Using a dynamic web tooling product at the moment, and at first I was enthusiastic, but it's crippled compared to VB6
Basically, a formalization of Dagger/Guice into a language.
There are some examples, e.g. the Bevy ECS doing more or less dependency injection for you (and ensuring against things like aliased mutable references), which is pretty neat.
Reminds me of implicit parameters in Scala - https://docs.scala-lang.org/tour/implicit-parameters.html
Edit: I think I like it. It doesn't solve dependency injection like e.g. Guice but the examples given, e.g. providing implementations for traits defined in external crates that take arbitrary state, is compelling.
https://itnext.io/hmock-first-rate-mocks-in-haskell-e59d7c3b...
What other ways do you have in mind?
I am not aware of any Haskell functionality or compiler flag that enables implicit parameter passing, like Java, Kotlin, and Rust allow.
An approach to do it statically is with implicit parameters. Scala has them, for example.
vector = array [1..25] of real; real :: vector(-2:5)
declares an 8-element array with bounds -2 and 5.See Calca: http://calca.io
And it still gives you the image editing tools (pixel editing for MakeCode), asset management, game loop, etc – all of which are too much to take on for a new programmer, but are really helpful, and hopefully make it feel like less of a regression.
The R and Julia syntax are better than Python for vectorized operations, although NumPy and Pandas mostly make up for it using the magic methods.
In terms of keystroke efficiency, nothing beats the array languages. One might think APL is a little too terse, whereas Pandas is a little on the verbose side.
E.g. contracts language could mean better understanding of substructural stuff so we can handle "real resources". But coming up with some syntax for this is the last step.
Definitely qt, right? https://www.qt.io/
And HTML/CSS :downtrodden-developer-with-woozy-face:
Well there are many of them like MATLAB, IDL, scilab, R and others. Python is verbose because it's not a calculator language but a general purpose language. I find J unreadable.
The great thing about R is that it scales well with task difficulty. It works well for a couple numbers. Then you can use data frames, and the Tidyverse (https://www.tidyverse.org/) packages to do a lot of data analysis (especially dplyr, which is extremely powerful). Finally, if you want to look at your data, the built-in plotting capabilities are solid, and ggplot2 is both extremely powerful and reasonably easy to use.
> import math prod([math.factorial(x) for x in l]) No! Bad python! In J it’s just / ! l, quite literally an order of magnitude fewer keystrokes.
I don't know anything about `match.factorial()` or `prod()` but I can deduce what it's doing. `/ ! l` is nonsense.
I thought linked lists were one of the easier data structures to implement? Is he saying they're annoying to use or implement here?
Unless you are a Rustacean…
https://blog.adacore.com/i-cant-believe-that-i-can-prove-tha...
HN discussion: https://news.ycombinator.com/item?id=31975507
This is sort of an odd thing to want. You need a diversity of data structures. And BTW the acronym not withstanding, lisp represents graphs not lists.
You said: "lisp represents graphs not lists". I think you meant that Lisp's defining data structure, based on the cons, was for general graphs, not lists. But that is not really true. If what you meant was "Lisp isn't just restricted to linked lists", sure, but that's true of every programming language with object arrays. So what?
Linked lists, trees, and heaps are all just graphs with certain requirements about their structure.
Everything else can be represented as a graph, just not as elegantly.
Also as a data point, I really really wish there was an everything is a graph language. I work in graphs all day (in the private industry) and I have to keep modeling them as arrays. It's a pain.
Edit: I've posted this same comment in multiple places in this conversation to get feedback from specific commenters, not as spam (it's a old personal project)
This already exists: programming languages that supports refinement types. Examples are Liquid Haskell and F* (F-star).
;; -*- mode: Emacs-Lisp; lexical-binding: t; -*-
You can then opt into dynamic scope for single variables, when it makes sense: (defvar variable)Additionally, Kernel has dynamic binding built-in, and done in a nice way. You never explicitly access a dynamic variable but you only have an accessor function to it. A new scope is created when binding a dynamic variable, and the accessor will return whatever was bound anywhere in the dynamic extent of this scope.
($define! (with-str get-str) (make-keyed-dynamic-variable))
($define! f
($lambda ()
(print (get-str))))
(with-str "Hello, world!"
($lambda ()
(f)
(with-str "Goodbye, world!" f)
(f)))
Prints "Hello, world!" "Goodbye, world!" "Hello, world!"Perhaps the only downside to this is that a runtime error will be raised if `get-str` is called before a value is bound. I think it would be a bit nicer to include a default binding as an argument to the call of `make-keyed-dynamic-variable`.
Haskell and lenses is pretty nice here.
Svelte (javascript framework) has reactivity build in.
- Idris (dependent types rather than contracts, but squint and the UX is the same) - Python's decorators enable some of this, but Aspect oriented programming may also be what they are looking for. Boomerang is totally different but also an exploration in this space. - Io, or even JavaScript fit this description - there's a calculator like this I am forgetting the name of at the moment - this looks like Dependent typing to me, see Idris above
For a fully dynamic scripting language, look no further than Python.
Function inheritance? We have decorators in Python already, and most functional languages support seamless function composition. Take your pick between Haskell, Lisp, Scala and even Rust.
Designing a new languages needs to have a pragmatic purpose and sometimes, valid ideology.
IIRC Objective-C can bind new methods at runtime
Nearly all common languages like Python, JS, Java, OCaml, etc. let you express graphs with records / objects. Everything is a graph!
If you want a homogeneous graph, you just declare a single node type, like
class Node:
edges: List[Node] # or maybe Dict[str, Node] if you want them to be named
payload: int
- Or you can have a heterogeneous graph with many different node types.- If you want to label the edges, you can reify them as their own type
The whole heap is graph-shaped!
It's true that many programs in these languages are more tree-like than graph-like. And sometimes imperative code to manipulate graphs is hard to visualize.
But I think there doesn’t need to be a separate language of graphs for this reason.
---
If you want to see graphs done in plain C, look at this DFA code by Russ Cox:
https://swtch.com/~rsc/regexp/regexp1.html
e.g. Implementation: Compiling to NFA
(copy of lobste.rs comment)
A graph isn't defined as a list of nodes. A list is defined as a directed graph where each node has one vertex in each direction.
A list is defined as a directed graph where each node has one vertex in each direction.
That definition works equally well for existing languages, e.g.
struct Node {
struct Node *prev, *next;
int payload;
}:
The types gives you some constraints on the shape of the graph.There needs to be a J# project lmao
Meta
We could express this as an adjacency list like
Graph{
1 <-> 2
1 <-> 5
2 <-> 3
2 <-> 5
3 <-> 4
4 <-> 5
4 <-> 6
}
So there's already a lot of repetition of the node labels, but in real life applications you would probably have actual data associated with each node (like maybe a user_id, or a name, etc, whatever the "elements" of your graph are). Actually, you would in most cases have some key that identifies the node (like user_id), and some other data associated with the node (like date of birth, locale, etc). So the above notation would force some kind of notation like: ("user1", (1970, USA)) <-> ("user2", (1980, UK))
("user1", (1970, USA)) <-> ("user5", (1990, RU))
...
So now the notation would require not only repetition of the node name, but also the data itself. This would be even more of a problem if the data was not a literal but was computed, like:
("user2", (getDateOfBirth("user2"), getLocale("user2"))So then the way around this would be to use the programming language's own variable/identifier system, like
var user1 = ("user1", (1970, USA))
var user2 = ("user2", (1980, UK))
var user5 = ("user5", (1990, RU))
Graph{
user1 <-> user2,
user1 <-> user5,
...
}
or perhaps some other node registration system, and then just repeat the labels Graph{
Nodes {
("user1", (1970, USA)),
("user2", (1980, UK)),
("user5", (1990, RU)),
...
}
Edges {
"user1" <-> "user2",
"user1" <-> "user5",
...
}
}
So now we've avoided repeating data, but we still have to repeat nodes. In some situations, a different way of expressing a graph would also be preferable to adjacency lists (you might want an adjacency table, but in sparse graphs the list is more efficient)but by the way, for your graph system to be generally useful, you'll have to come up with a syntax and flexibility of design that ergonomically allows graphs that vary in:
directedness: support for undirected and directed edges edge wights and data: edges could be identical or they could have weights or even keys and other attributes associated with them
graph/multigraph: can there be multiple edges between the same 2 nodes?
in statically typed languages, the data type of the "key" of the nodes, the "value" of the nodes, the "key", "value" of the edges, all have to be represented to some degree in the language's type system, so at least 4 generic parameters in a graph
So, seems that there is just a huge design space and a variety of different usecases that makes coming up with a simple solution to the general problem very difficult.
Edit: I've posted this same comment in multiple places in this conversation to get feedback from specific commenters, not as spam (it's a old personal project)
He wants contracts which is basically dependent types. These rules live in types and already exists in agda, Idris and coq and has a range of tradeoffs.
Essentially these languages can enforce static checks and "contracts" so powerful you don't need unit tests. These "contracts" cover more ground and are safer then tests. The tradeoff is you need a big brain and lots of time to write these things.
Then he wants a language that is truly dynamic. Which is like the opposite.
Think of it like 1*2 && 2. Both expressions are isomorphic. Dependent types literally encompasses everything he wants.
Dependent types are not doable in assembly though. Assembly has no notion of types. The claim that all languages are equivalent because they're turing complete has absolutely no relevance here. While true in terms of capability, the syntax and semantics of languages do make them different. One can add a contract library to idris. You cannot do that to assembly code because asembly code as a library. Such a thing is nonsensical since assembly's compilation model has no notion of type checking.
Assembly language does not have types. What you can do is create a new language with assembly and have that language have types. The reason why it has to be done this way is because these types of checks CANNOT happen at runtime. It's a pre-runtime check that prevents the code from even running if it's not correct.
Think about it. Can you add types to assembly language without creating a new language? No.
No one is saying assembly language cannot be used to write a dependently typed language system, with a type checker and runtime (which are one and the same in a DT language anyway). However, that does not make assembly language dependently typed.
You are committing the logical error of assuming that the result of a process means inputs to the process are equal to the outputs. Just because I could take grain and make it into bread doesn't mean grain is equivalent to bread.
This is exactly what dependently typed languages like coq and idris are attempting to do. What he wants ALREADY exists and these things are trying to fulfill EXACTLY his intent. I am not attempting to talk about some obscure isomorphism.
You also cannot build all 6 things in any number of languages unless you are using those languages to build new languages. These checks exist at the type level, not at runtime, but pre-compile time.