Live data from Hacker News

Rust vs. Haskell

serokell.io

51–60 of 189 posts

Re: Rust vs. Haskell

#51
post #36

Earlier quoted context omitted.

Quite a few of Rust's features were borrowed from or inspired by ones in Haskell - albeit often modified to be more suitable for systems programming (and systems programmers!). Most Haskellers I know are quite fond of Rust :)

IMO, that's too superficial to compare them. So what if both have a bunch of similar looking constructs? Rust is imperative, and sequential, and nearly everything is mutable, hence the borrow checker. That makes programming in Rust rather different.

Rust is immutable by default. You have to deliberately opt in for mutability. When you don't opt in to mutability the programming styles are very similar at a basic level.

First the type system is very similar with the capability of building sum and product types with recursive values. Second pattern matching over sum types is also very very similar.

Rust is like the bastard child of C++ and haskell.

Re: Rust vs. Haskell

#52

Earlier quoted context omitted.

> it ensures that you're passing and returning the proper type to and from the function You don't need it for all function declarations though, there are many trivial cases where type signatures don't add value. Consider that you probably would prefer most of the variables within a function to be inferred for you by the compiler. A similar thing could be said about the most of the functions within a given module. Imp…

pub functions: should be explicit module functions: if I chose, I'd let them be derived, but I'm relatively indifferent inner functions: should be allowed to be derived, IMO. They're very infrequently used so this choice doesn't have much impact.

You can use closures as functions with type inferred signatures

Re: Rust vs. Haskell

#53
post #43
post #21

Earlier quoted context omitted.

I think painting Rust and Haskell as similar languages is very misleading. Haskell has a garbage collector for a reason. You can't program naturally with closures unless you have a garbage collector, because closures introduce cyclic references. Also, Haskell has a type inference system that allows e.g. the IO monad to work seamlessly with the rest of the language. EDIT: and laziness of course.

You should look at what you can do with the Rust type inference too, it's not too far away from Haskell, at least not superficially. For example using the return type to deduce type parameters for a method like let samples: Vec = iterator.collect();

But this is the most trivial example of inference. Rust has neither generic implementation of higher kinded data nor global inference for the existing specific cases of it like GAT.

Re: Rust vs. Haskell

#54

> if we have a map and want to do some operation on a slightly modified map, we can have a value that keeps the old map but also works with the new map (without much performance cost). What black magic is this? Is the article just glossing over the cost of a copy or does Haskell do something weird here to avoid the copy while retaining both versions?

I can't speak for Haskell as I haven't looked at their implementation, avoiding copies is pretty typical of immutable data structures. Because each component of the data structure is immutable, you can safely point to any part of the structure that you don't need to change rather than copy it.

For example, in a basic binary search tree implementation of a map (using C-ish syntax for those who don't know a functional language):

    struct Node {
      String key;
      int value;
      Node left;
      Node right;
    }

    Node set(Node n, String key, int value) {
      if(n == null) {
        return new Node { key = key, value = value, left = null, right = null };
      }

      if(key  n.key) {
        return new Node {
          key = n.key,
          value = n.value,
          left = n.left,
          right =  set(n.right, key, value)
        };
      }

      return new Node { key = key, value = value, left = n.left, right = n.right };
    }
A perfectly-balanced tree with depth of 5 has 1 + 2 + 4 + 8 + 16 = 31 nodes. If you call the above function, on such a tree, the worst case scenario is that the key doesn't exist, so it modifies 5 nodes during its search and creates a new sixth node. 26 of the original 31 nodes are reused and referenced by the newly-created map. The percentage of nodes reused only improves as the perfectly-balanced tree gets larger.

Of course, if this is your implementation of set(), the tree won't be perfectly-balanced, so a production implementation of a tree-based map needs tree-rebalancing (as well as memory-reordering and compacting for cache locality). These extra constraints typically mean less of the tree can be re-used, but the percentage of nodes which can be reused remains high.

Re: Rust vs. Haskell

#55

"What do you use Haskell for?" Most important question about Haskell

I know it is common to think that Haskell is used only in academia and side/weird-projects, but there is a decent amount of companies using Haskell - e.g. we use Haskell in production for developing a DSL / web framework for building web apps (https://github.com/wasp-lang/wasp)!

I participated teaching students Haskell on my alma mater this year and "what can Haskell be used for" was a common question, with genuine expectation that the answer will be it is limited to only specific use cases. I would answer that it can be used anywhere where languages like Java, C#, Go, and similar can be used -> it is a general programming language that uses garbage collector! And while somewhat harder to learn due to abstractions that we are all not used to, it is a delight to express business logic in it once you get to know it well.

The biggest factor for deciding if Haskell is a good fit for the problem is probably ecosystem support -> are there enough libraries and tools to support efficient development in a specific problem domain. In our case, we are building a compiler/transpiler, and Haskell is well-known for great support in that area, so it was a no-brainer. We were actually also considering Rust, but we just had no need for that level of memory control and rather decided to go with language where we don't have to think about that (Haskell).

Re: Rust vs. Haskell

#56
post #21

Earlier quoted context omitted.

I think painting Rust and Haskell as similar languages is very misleading. Haskell has a garbage collector for a reason. You can't program naturally with closures unless you have a garbage collector, because closures introduce cyclic references. Also, Haskell has a type inference system that allows e.g. the IO monad to work seamlessly with the rest of the language. EDIT: and laziness of course.

Rust has closures and does not use a GC. The borrow checker just makes sure that a closure never outlives its captures or any of its references. The most prominent difference between Rust and Haskell is that Haskell uses lazy evaluation throughout; it's the language's unique selling point. Rust doesn't even have generators in the stable variety of the language yet, although they are internally used to implement async…

> The borrow checker just makes sure that a closure never outlives its captures or any of its references.

The point is that the borrow checker forces you to program in a fundamentally different style than idiomatic Haskell.

Re: Rust vs. Haskell

#57
post #21

Earlier quoted context omitted.

I think painting Rust and Haskell as similar languages is very misleading. Haskell has a garbage collector for a reason. You can't program naturally with closures unless you have a garbage collector, because closures introduce cyclic references. Also, Haskell has a type inference system that allows e.g. the IO monad to work seamlessly with the rest of the language. EDIT: and laziness of course.

Rust has closures and does not use a GC. The borrow checker just makes sure that a closure never outlives its captures or any of its references. The most prominent difference between Rust and Haskell is that Haskell uses lazy evaluation throughout; it's the language's unique selling point. Rust doesn't even have generators in the stable variety of the language yet, although they are internally used to implement async…

There is nothing "natural" about working with Rust closures. If you want to take a losing fight against the borrow checker, they are the best way to do it.

(Rust has your C-like run of the mill function references too. People should emphasize those more, because differently from closures, those work very well.)

Re: Rust vs. Haskell

#58

As a systems programmer any mention of the word Haskell next to the word Rust sends shivers down my spine. Haskell is the king of yak shaving abstractions and is almost the polar opposite in all the ways that made C the most practically successful language on the earth. I do not want abstractions where they aren't needed. I want control, simplicity, a clear correspondence between what I'm writing and what logical ass…

I've helped write some very abstract combinator-y Rust that compiled down to an embedded program that runs with only 4K RAM. Get over it.

> and what logical assembly I'll be generating

The problem with Rust and C is not worrying about what assembly I'll get, it is that one has very little control over the layout of the stack. It's the last implicit data structure and that's a PITA for highly resource constrained programming.

Re: Rust vs. Haskell

#59

> if we have a map and want to do some operation on a slightly modified map, we can have a value that keeps the old map but also works with the new map (without much performance cost). What black magic is this? Is the article just glossing over the cost of a copy or does Haskell do something weird here to avoid the copy while retaining both versions?

A compiler can do a huge amount of black magic when the order of evaluations is not guaranteed.

And GHC exploits that liberty.

Re: Rust vs. Haskell

#60

As a systems programmer any mention of the word Haskell next to the word Rust sends shivers down my spine. Haskell is the king of yak shaving abstractions and is almost the polar opposite in all the ways that made C the most practically successful language on the earth. I do not want abstractions where they aren't needed. I want control, simplicity, a clear correspondence between what I'm writing and what logical ass…

Rust is the bastard child of C++ and Haskell.

So it doesn't have the simplicity of C, it tries to give you as many abstractions as possible while still maintaining the zero cost philosophy.

I would say Rust is easier then C++ and easier haskell.

Post reply on HN