3 ms·
>Haskell (and OCaml etc) give you both straightjackets.. Haskell's thing with purity and IO does not feel like that. In fact Haskell does it right (IO type is
by qsera 10mo ago
>Haskell (and OCaml etc) give you both straightjackets..
Haskell's thing with purity and IO does not feel like that. In fact Haskell does it right (IO type is reflected in type). And rust messed it up ("safety" does not show up in types).
You want a global mutable thing in Haskell? just use something like an `IORef` and that is it. It does not involve any complicated type magic. But mutations to it will only happen in IO, and thus will be reflected in types. That is how you do it. That is how it does not feel like a straight jacket.
Haskell as a language is tiny. But Rust is really huge, with endless behavior and expectation to keep in mind, for some some idea of safety that only matter for a small fraction of the programs.
And that I why I find that comment very funny. Always using rust is like always wearing something that constrains you greatly for some idea of "safety" even when it does not really matter. That is insane..
- gpm 10mo ago> "safety" does not show up in types It does in rust. An `unsafe fn()` is a different type than a (implicitly safe by the lack of keyword) `fn()`. The difference is that unsafe fn's can be encapsulated in safe wrappers, where as IO functions sort of fundamentally can't be encapsulated in non-IO wrappers. This makes the IO tagged type signatures viral throughout your program (and as a result annoying), while the safety tagged type signatures are things you only have to think about if you're touching the non-encapsulated unsafe code yourself.
- qsera 10mo ago>The difference is that unsafe fn's can be encapsulated in safe wrappers This is the koolaid I am not willing to drink. If you can add safety very carefully on top of unsafe stuff (without any help from compiler), why not just use `c` and add safety by just being very careful? > IO tagged type signatures viral throughout your program (and as a result annoying).. Well, that is what good type systems do. Carry information about the types "virally". Anything short is a flawed system.
- gpm 10mo ago> This is the koolaid I am not willing to drink. > If you can add safety very carefully on top of unsafe stuff (without any help from compiler), why not just use `c` and add safety by just being very careful? There is help from the compiler - the compiler lets the safe code expose an interface that creates strict requirements about how it is being called with and interacted with. The C language isn't expressive enough to define the same safe interface and have the compiler check it. You can absolutely write the unsafe part in C. Rust is as good at encapsulating C into a safe rust interface as it is at encapsulating unsafe-rust into a safe rust interface. Just about every non-embedded rust program depends on C code encapsulated in this manner. > Well, that is what good type systems do. Carry information about the types "virally". Anything short is a flawed system. Good type systems describe the interface, not every implementation detail. Virality is the consequence of implementation details showing up in the interface. Good type systems minimize the amount of work needed to use them. IO is arguably part of the interface, but without further description of what IO it's a pretty useless detail of the interface. Meanwhile exposing a viral detail like this as part of the type system results in lots of work. It's a tradeoff that I think is generally not worth it.
- qsera 10mo ago>the compiler lets the safe code expose an interface that creates strict requirements about how it is being called with and interacted with.. The compiler does not and cannot check if these strict requirements are enough for the intended "safety". Right? It is the judgement of the programmer. And what is stopping a `c` function with such requirements to be wrapped in some code that actually checks these requirements are met? The only thing that the rust compiler enables is to include a feature to mark a specific function as unsafe. In both cases there is zero help from the compiler to actually verify that the checks that are done on top are sufficient. And if you want to mark a `c` function as unsafe, just follow some naming convention... >but without further description of what IO it's a pretty useless detail of the interface.. Take a look at effect-system libraries which can actually encode "What IO" at the type level and make it available everywhere. It is a pretty basic and widely used thing.
- elbear 10mo agoWhen I started learning Haskell, it did feel like coding with a straightjacket.
- qsera 10mo agoI think that is because when you start learning Haskell, you are not typically told about state monads, `IORefs` and likes that enables safe mutability. It might be because Monads could have a tad bit advanced type machinery. But IORefs are straightforward, but typically one does not come across it until a bit too late into their Haskell journey.
- eru 10mo ago> You want a global mutable thing in Haskell? just use something like an `IORef` and that is it. It does not involve any complicated type magic. But mutations to it will only happen in IO, and thus will be reflected in types. That is how you do it. That is how it does not feel like a straight jacket. Haskell supports linear types now. They are pretty close in spirit to Rust's borrowing rules. > Haskell as a language is tiny. Not at all. Though much of what Haskell does can be hand-waved as sugar on top of a smaller core.