> Monads are not some kind of obscure math-y thing that only the big brains think are necessary. No, instead monads are a fundamental abstract algebraic description of imperative programming as a computational context.
Yep, as a non-big-brainer, I definitely get it now. :)
1. Go, when I first saw code I wrote almost a decade ago still compiles and runs in Go, I decided to use Go for everything. There were some initial troubles when I started using it a decade ago, but now it's painless.
2. Haskell, I use it for DSL and state machines.
3. Bash for all deployment scripts and everything.
4. TypeScript, well for the frontend.
Lately, I’ve been using Go and SQLite for nearly everything.
I don't think I’ve any motivation to look at any other language.
I gave up on Java, Python, Ruby, Rust, C++, and C# long ago.
Fun fact:
Same thing for cloud, I just don't use managed cloud services anymore. I only use VMs or dedicated servers. I've found when you want to run a service for decades+, you’ve got to run your own service if you want it not to cost a lot in the long run.
I manage a few MongoDB, PostgreSQL clusters. Most of the apps like email lists marketer (for marketing, sending thousands of email each day) are simple Go app + SQLite using less than 512MB RAM.
Same for SaaS billing, the solution is entirely written in Go and uses Postgres. (I didn’t feel safe here using SQLite for this for a multi-tenant setup.)
Our chat/ticketing system is SQLite + Go. Deployment is easy, just upload Go cross-compiled binary + systemd service file, alloy picks up log and drops it graphana which has all alerts there.
I don't need to worry about "speed" for anything I do in Go, unlike Ruby/Python.
When something has to be correct I define it model it in Haskell as its rich type system helps you write correct code. Though setup is not painless as Go, decent performance.
I write good documentation, deployment instructions right into mono repo. For a small team this is more than enough imho.
No Docker, no Kubernetes, just using simple scripts + graphana + prometheus + Loki and for alloy/nodeexporter. Life couldn't be any simpler than this.
But, flipping the script, if you want to see something like Zig's `Io` interface in Haskell then have a look at my capability system Bluefin, particularly Bluefin.IO. The equivalent of Zig's `Io` is called `IOE` and you can't do IO without it!
https://hackage-content.haskell.org/package/bluefin-0.5.1.0/...
Regarding custom allocators and such, well, that could fit into the same pattern, in principle, since capabilities/regions/lifetimes are pretty much the same pattern. I don't know how one would plug that into Haskell's RTS.
fn Maybe(comptime T: type) type {
return union(enum) {
value: T,
nothing,
const Self = @This();
pub fn just(the_val: T) Self { return .{ .value = the_val }; }
pub fn nothing() Self { return .nothing; }
}
}
Over this? data Maybe a = Just a | NothingIn my opinion, the concept of automaton is fundamental and it deserves equal standing with the concept of function (even if it is a higher level concept that is built upon that of function).
I believe that functional programming is preferable wherever it is naturally applicable, and most programs have components of this kind, but most complete application programs, i.e. which do input and output actions, are automata, not functions and it is better to not attempt to masquerade this with tricks that provide no benefits.
Therefore, I prefer a programming language that has a pure functional subset, allowing the use of that subset where desirable, but which also has standard imperative features (e.g. assignment), to be used where appropriate.
- Go - backend + CLIs
- TypeScript - fronted, occasionally zx for more complex scripts
- Nushell as my scripting language (I’ve been relentlessly using it everywhere I can instead of bash/zsh and man it is such an improvement)
I heard so much good stuff about both Zig and Rust and would love to eventually get to know one of them.
It's dependency injection. and yes, you can model dependecies like a monad but most people, even in less pure fp langs, don't.
i don't really say this to just be a pedant, but if you're an fp enjoyer, you will be disappointed if you get the picture that zig is fp-like, outside of a few squint-and-it-looks-like things
I don't think this even qualifies as correlation.
a function from a set X to a set Y assigns to each element of X exactly one element of Y.
[https://en.wikipedia.org/wiki/Function_(mathematics)]I would take another look at Common Lisp if I were the author. Manual memory management is very much an option where you need it.
I opened the network log, disabled cache and reloaded to see it only transferred 8kb.
Keep up the good work!
> ...
> What facilities does the language provide me to create correct-by-construction systems and how easily can I program the type-system.
Isn't programming the type-system orthogonal to the program's domain in the same way that manual memory management is?
I actually ship stuff in Haskell believe it or not. I also think Zig is very cool and have played around with it quite a bit. Yes, garbage collection hurts performance, but the reality is that the overwhelming majority of all software does not suffer from the performance loss between well written code in a reasonably performant functional gc language and a highly performant language with manual memory management. It’s just not important. But not having to deal with the cognitive overhead of managing memory and being able to deal in domain specific abstractions only is a massive win for developer productivity and code base simplicity and correctness.
I think OxCamls approach of opting in to more direct control of performance is interesting. I also think it’s great that many functional patterns are making their way into imperative first languages. Language selection is always about trades offs for your specific use case. My team writes Haskell instead of Rust because Haskell is plenty fast for our use case and we don’t have to write lifetime annotations everywhere and think about borrowing. If we needed more performance we would have no choice but to explore other languages and sacrifice some developer experience and productivity, that’s very reasonable. I’m also not saying performance doesn’t matter (if you’re writing for loops in Python, stop). But this read to me like “because better performance exits with manual memory management, all garbage collectors are bad, so I’ll force zig to be something it’s not in order to gain performance I probably don’t need”. Which to me is an odd take. A more measured way of thinking about this might be, it can be useful to leverage functional patterns where appropriate in low level languages, if you find yourself needing to write code in one.
Can comptime blow up compile times? Does it have arbitrary cutoffs like C++ template depth?
I am definitely in the minority here, but I am not a fan of the kind of meta-programming that Zig and Rust offer, with Rust being especially atrocious. In the two decades I've been programming I can count on one hand the number of times meta-programming was an appropriate solution to a problem I had. Every time I reached for it, I got bit. There's a reason "when in doubt, use brute force" is sage advice, it may not be fast and glamorous, but it'll be a hell of a lot less opaque.
Honestly this sounds like monad bullshit. That's a struct/class/ADT/whatever you want to call it, they existed since forever. The only idea Zig had was that maybe we shouldn't make them global instances.
In addition to the normal value to value, type to type, and type to value functions, in comptime, you can write static value to type functions.
In full dependent type, you can in addition write dynamic value to type functions, completing the value to type corner.
So in terms of typing strength, plain Haskell < Zig < dependent type languages.
I haven't heard anyone writing code in Elixir complain about performance issues.
Why write:
EqPoint.eql(a, c)
When you can write:
Point.eql(a, c)