Hacker News new | ask | show | jobs
by axilmar 2115 days ago
My personal experience with Haskell hackers went like this:

-I used to hang out at lambda-the-ultimate, in which haskell was considered god sent and c++ a toy language. At the time, I was heavy into writing simulation software, which meant c++ all the way, so I tried to understand haskell and its advantages over c++, but my attempts ended up being mocked. I stopped visiting that site.

-I tried to open some debates about Haskell on reddit, where someone told me they will answer my haskell questions only if I told them a specific mathematical definition on some properties of functions. I didn't know the reply, I was a programmer after all, not a mathematician. Said person left me in the cold.

-again on reddit, I was trying the debate the usefulness of haskell regarding simulation software, which relies heavily on updating variables, but I never got straight answers. To this day, I still do not know if haskell code actually can update variables in place or it only simulates updating of variables. Someone suggested using lens, and although I understand the abstraction, it still has not solved my question if haskell can update variables in place.

Why I was so interested in this aspect, i.e. in place updating? I wrote simulation software and after that game software for a living, and it matters to me because I want to be able to reason about the performance of my program. I don't want to have data be duplicated behind my back.

To cut the long story short, my haskell questions go unanswered to this day, I was very disappointed, and since I have great experience in imperative programming languages, I usually write programs that are correct as soon as they are compiled, which is what the haskell advantage is supposed to be. So I don't see any benefit from haskell, and I won't recommend it to my company or my colleagues.

Am I wrong regarding haskell? perhaps, but I am not interested any more in 'trying out' languages of dubious gains, nor am I interested in dealing with juvenile behaviors. I tried Rust because it had a serious advantage over C++ (namely, object lifetimes), and I will recommend Rust, but my patience for and interest in haskell is virtually non-existent at this point.

4 comments

I personally haven't had the same experience as you (I personally find the Haskell community quite pleasant, especially in the functional-programming slack server), but I'll try and answer (probably in an incomplete way) your question about updates.

Haskell can, in fact, update variables. Mostly through 2 mechanisms:

- ST (a computation containing local, mutable state, that cannot escape its scope) [1]

- IORef (mutable, thread-safe variables that only work in IO). [2]

The other (and usually more common way) of doing "mutable" state in Haskell is through State, which technically doesn't update the variable in-place, but simply modifies the variable and passes a copy to the rest of the computation (although, as far as I'm aware, a lot of the time this step gets optimized away).

That said, if your main field of expertise is simulation programs where performance and space efficiency are very important, then Haskell is probably not a great fit (cause not only is it based on a GC, it's also lazy, which can sometimes mess with the performance of your code, not speed-wise but memory usage-wise). Hopefully this could be mitigated in some way in the coming years when Linear types become viable for efficient resource usage (Linear types ideally could grant us some sort of Rust-like resource management)

[1] https://hackage.haskell.org/package/base-4.14.0.0/docs/Contr...

[2] https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-...

As one who wrote a couple hardware simulators in Haskell and otherwise, I have to disagree with you.

The very immutability of Haskell values means one has to use transactional logic - given current situation, compute situation at next step. C++ and many other languages tend to update values in-place and that brought me a lot of bugs to debug and, subsequently, made me use Haskell.

Laziness plays a critical role in free composition of parts of the system.

Let me present you some examples.

Single clock domain computing hardware can be thought as computations that compute values for every raising edge of a clock. It can be described as a function from infinite list of inputs to infinite list of outputs. The adder, for example, is just like this:

  adder :: Num a => [a] -> [a] -> [a]
  adder = zipWith (+)
The register is a thing that produces values remembered from the previous clock cycle. The very first value comes from reset:

  register :: a -> [a] -> [a]
  register = (:)
Mealy machine allows you to apply a function that transforms input and internal state into output and next internal state. Mealy machine can be used for description of all kinds of things, from register files upwards.

  mealy :: ((input, state) -> (output, state)) -> state -> [input] -> [output]
  mealy f resetState inputs = outputs
    where
      -- here comes shortcircuiting that relies on laziness:
      outputsAndStates = map f (zip inputs (register resetState states))
      outputs = map fst outputsAndStates
      states = map snd outputsAndStates
That's it!

Using regular map and other list functions and these two additions, one can simulate single clock domain hardware which amounts to almost anything that computes on silicon - within bounds of approximation; basically, one need to add delays for slower hardware somehow.

The trick with shortcircuiting above allows one to freely compose hardware simulation from different parts. You just put blocks there and they start to work. The function in Mealy machine is pure and total and can be tested (or verified) thoroughly in standard simple way.

From what I read here:

https://stackoverflow.com/questions/57489844/how-does-readio...

IORef does not allow a value to mutate, it allows a pointer to a value to mutate.

Am I correct?

Does the ST Monad work in the same way? or does it truly allow values to be updated in place?

IORef is a pointer to value that can be changed. IORef holds pointer to a value (boxed value) because most Haskell values are lazy.

Please look at unboxed vectors for another example: https://hackage.haskell.org/package/vector-0.12.1.2/docs/Dat...

You can create an unboxed mutable vector and read and update its elements. Vectors are stored as Structure Of Arrays (Vector (a,b) is transformed into (Vector a, Vector b)) and are very efficient in transformations.

Next to them you can find Storable vectors which allow you to store and update any values that have Storable class instance defined. They are for cases when you need Array Of Structures.

Continuing Vector example, ST monad allows you to create a computation that uses mutation internally and looks pure from outside - do new/read/write and then return freezed array. Apply ST monad runner and you get pure freezed array. IO monad allows you to pass that array between computations of different kind.

Sorry to hear about your experience. I hang out on Haskell Reddit a lot. If you link me to the particular Reddit threads in question that will help me understand the situation better and I'll try to prevent anything similar happening again.

To address your more specific question, yes, Haskell can mutate data in place. See, for example, https://hackage.haskell.org/package/vector-0.12.0.1/docs/Dat.... On the other hand, unless you've got another compelling reason to use Haskell one wouldn't tend to say that Haskell stands out as a language to implement that kind of thing in.

[EDIT: Having looked at your history of commenting about Haskell on Reddit I'm not surprised that people took offence.]

My seemingly offensive comments came after I received seemingly offensive comments from others. It's very rare that I start discussions by offensive comments.

I start discussions by disagreement though. If that is deemed offensive, what can I say.

For posterity can you link to the questions that went unanswered on r/Haskell? I'd like to do an analysis.
> I have great experience in imperative programming languages, I usually write programs that are correct as soon as they are compiled, which is what the haskell advantage is supposed to be.

Same here. It's simply not worth switching. And also Haskell is probably not going to provide much more productivity in lots of areas.

I'd argue if you can manage to write 10,000 line imperative programs that are correct as soon as they are compiled:

1) that's amazing, some of us aren't smart enough to do it without functional programming

2) I bet you could write 2-3x as much functional code and maintain the correctness. Reason being understanding doesn't require keeping track of mutable states in your head.

No one writes 10000 line programs, either imperative, or functional, without testing and running smaller parts of it. At least no one that I know of.

I have dealt with ML while doing my MSc in software engineering, and wrote my dissertation on it.

I didn't see any improvement regarding bugs and state.

What I have discovered in functional languages is that while in fp you are not required to keep track of mutable states, you are required to keep track of values passed in parameters.

In my humble opinion, those two things are equal in difficulty and consequences.

I had almost the same number of bugs in my ML application that I would have in the imperative program, but they manifested in different ways.

I don't think FP requires the programmer to keep less things in their head, provided that the imperative program follows some good principles, that is.

> In my humble opinion, those two things are equal in difficulty and consequences.

I'm not so sure, I'll give this idea some thought though.

> I had almost the same number of bugs in my ML application that I would have in the imperative program, but they manifested in different ways.

Can you talk about some of the different ways the same bug manifested?

I didn't say 'the same bug manifested in different ways', I said 'same number of bugs but manifested in different ways'.

I.e. the defect ratio was similar, bugs in my FP program were of different type than in the imperative ones.