4 ms·
The whole point of Haskell as a programming language is to have lazy evaluation be the default. This comes with boxing data objects everywhere, which is the op
by zozbot234 2y ago
The whole point of Haskell as a programming language is to have lazy evaluation be the default. This comes with boxing data objects everywhere, which is the opposite of a focus on low-level performance. Haskell does support using strict, unboxed data but it's clunky and not the default. (Also, recent versions of Rust have now added support for "plug-in" laziness via the type constructors LazyCell<> and LazyLock<>.)
- benreesman 2y agoI’m aware of how boxing works in GHC, I learned it from Simon Marlowe. I don’t mean to be obtuse but I don’t see what that has to do with linear typing as a fucking weird mandatory default?
- zozbot234 2y agoI'm not sure what's supposed to be especially weird about linear typing (or rather, uniqueness typing which is what Rust ultimately relies on). If you want to see the use of such types in a language that's clearly even less "convenient" and more principled than Rust, you can look at Austral https://austral-lang.org/ https://austral-lang.org/
- benreesman 2y agoI think I’m going to be a hard pass on a language more militant about BDSM type system level memory management than Rust.
- deleted 2y ago[deleted]
- farmeroy 2y agoIs their code linter called whippy?
- the_duke 2y agoWhy should every language occupy the same design space? Rust was shaped by Mozilla wanting a language to replace parts of Firefox with. A language that is low-level enough to give very high performance, enforces correctness through the type system, and yet has many abstractions so it feels modern and convenient to use. Rust doesn't have any automatic allocations. You can wrap every type in `Arc<Mutex<T>>` and treat it like a very verbose Python, but that's the programmers choice. The design decisions have been validated by the success of Rust in certain domains. There is a reason why more than one programming language exists...
- benreesman 2y agoI think Rust is cool! If it wasn’t actively seeking world domination I’d be like, cool let’s use that sometimes. Rust is so hell bent on a Rust monoculture ranging from stuff like TRACTOR to actively opposing interop that a few of us who know our shit have to be like “easy now” once in a while. I’m trying to decide between tiktoken and sentencepiece for a new vocabulary at the moment, and it would be easier in some ways to go with tiktoken. But I want it to run faster than a fart at inference time, which means I’m linking libtorch, which means I’m writing C++. And fuck, link to Rust from C++? Let’s take another look at the Google stuff.
- zozbot234 2y ago> to actively opposing interop Rust just uses the C ABI for interop (including interop with Rust code that might not be part of the same build, such as dynamically-linked program objects). So you just have to come up with a plain C API for the interface and write wrappers on both sides of the divide that reference the C API. There are crates that will help with this, even achieving something like a "stable ABI" for Rust interop. (And we'll probably see some work into interop with Swift itself (which has a stable ABI of its own) once there's enough interest in that as a memory safe language.)
- benreesman 2y agoIt’s doable! But bindgen/cbindgen/cxx/etc exist for a reason: it hurts like a root canal. In my particular case, tiktoken is substantially like 600 lines of Rust. If I have a deadline do I fuck with the linker or just write it again? I’m marshaling std::string here, fuck let’s just write it. What I’m not going to re-write because I’m not a magnificent maniac like geohotz? I’m not going to rewrite libtorch. Which is written in C++ like all the software you can’t really live without.
- bananapub 2y agoperhaps a dumb question, but why does laziness imply boxing? or does 'boxing' in haskell mean something other than 'embed a simple bit of data in a fancy thing on the heap'?
- benreesman 2y agoA dramatic over-simplification is that a lazy value referenced by some continuation/thunk is hard to stack allocate in-situ. Now GHC does stack allocate, but it’s hard to count on without really aggressive hinting.
- the_duke 2y agoFunnily enough Rust supports exactly that pretty well with async. An `async {}` block is not evaluated, but converted into a generator/state machine that lives on the stack, and that has to be advanced by calling a poll method. You can move it to the heap , but that does not happen automatically. Sharing of values is obviously much more awkward due to mutability and no automatic cloning though.
- benreesman 2y agoI know how it works though I remain unconvinced that rustc is dealing with the same scope of problem as GHC in the general case. But to be clear, anyone with the username the_duke is probably really cool, and you clearly know your stuff as well as having style, so count me as a fan.
- bananapub 2y agoah, right, laziness can cause the control flow to become extremely complicated - makes sense, thanks!
- benreesman 2y agoAlso true! And in very real sense literally what I meant. But not so much in the conditional branch sense of the phrase “control flow”. More like, I’ve got a bunch of references and one of them is a reference to a function I might evaluate, damn, I need that reference and the transitive closure of everything it knows about, all of which are probably on the heap.