Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Took 10 mins to hack a silly, inefficient version.

https://play.golang.org/p/UPlzWR5OCO

Gives the same result as https://www.ietf.org/mail-archive/web/tls/current/msg03416.h... SHA256 test vector.

Looks easier to understand, to me...



It actually looked much more difficult to understand to me because golang just really has no structure.

Anyways, it probably is simpler, because it doesn't solve the same problem that the Haskell code solves. The Haskell code allows you to generate some bytes from the infinite stream even if you don't yet know how many you need; your go version must know how many you need before you start.

In order to do the same thing in go you're going to need to use an iterator or a goroutine + channel. Try doing that as cleanly as the Haskell version.


This can be done very easily using an unbounded io.Reader instead of channels or iterators.

Here's a slightly modified version of bluefox's code where the prf function returns an unbounded io.Reader: https://play.golang.org/p/ZAj8q4eXEi

And here's a version that's modified a bit more, but still essentially the same, to trade LOC for matching the spec very cleanly: https://play.golang.org/p/Rpy0yIwVN1


Just to be clear, a Pipe counts as a channel for me; like I said, it requires a goroutine. Don't get me wrong, this is definitely the "right" go implementation, and what GHC does internally with thunks is way worse than goroutines.

The point is it no longer looks so superior to the Haskell version, especially since there were many LOC in the haskell version just defining the Key datatype which go never does.


I don't see any kind of error handling, but if I understand correctly, in some cases in Go it is not necessary to check for errors directly (an errorneous output stream would do-nothing on write, for example). Do you think your versions are fault-tolerant or is there anything you should add to gracefully handle errors?


A Hash's Write method can't return an errors.

Writing and Reading to a pipe only errors if the pipe has been closed. We return an io.Reader, instead of an io.ReadCloser, so consumers can't close the Read side. Internally, the Write side is never closed either. So, in practice, Reading and Writing also won't ever error.


But is yours easier to reason about?

There is no doubt a steep learning curve with Haskell and FP in general. You may be thinking: what is all this <$> <*> and $ nonsense! However once learned, you can look at the Haskell code and it is more clear precisely what it is doing (and what it can't possibly do).

I think the article undersells Haskell. Haskell gives you code purity. Purity means you can reason about a function. A function that takes in an Int and returns an Int won't read data from your disk. It won't call a web service to get the answer. It won't update the counter int on your class and then one day cause it to overflow, causing another class that reads the counter int to throw an exception. This makes maintaining code a hell of a lot easier and more pleasant.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: