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

I guess my point is that you actually have to write the impure code somehow and it's hard, external world has tendencies to fail, needs to be retried, coordinated with other things. You have to fake all these issues. In your web server examples, if you need to a cache layer for certain part of the data, you really can't without encoding it to the state management tooling. And this point you are writing a lot of non-functional code in order to glue it together with pure functions and maybe do some simple transformation in the middle. Is it worth it?

I have respect for OCaml, but that's mostly because it allows you to write mutable code fairly easily.

Roc codifies the world vs core split, but I'm skeptical how much of the world logic can be actually reused across multiple instances of FP applications.



There's a spectrum of FP languages with Haskell near the "pure" end where it truly becomes a pain to do things like io and Clojure at the more pragmatic end where not only is it accepted that you'll need to do non functional things but specific facilities are provided to help you do them well and in a way that can be readily brought into the functional parts of the language.

(I'm biased though as I am immersed in Clojure and have never coded in Haskell. But the creator of Clojure has gone out of his way to praise Haskell a bunch and openly admits where he looked at or borrowed ideas from it.)


> external world has tendencies to fail, needs to be retried, coordinated with other things.

This is exactly why I'm so aggressive in splitting IO from non-IO.

A pure function generally has no need to raise an exception, so if you see one, you know you need to fix your algorithm not handle the exception.

Whereas every IO action can succeed or fail, so those exceptions need to be handled, not fixed.

> You have to fake all these issues.

You've hit the nail on the head. Every programmer at some point writes code that depends on a clock, and tries to write a test for it. Those tests should not take seconds to run!

In some code bases the full time is taken.

  handle <- startProcess
  while handle.notDone
    sleep 1000ms
  check handle.result
In other code-bases, some refactoring is done, and fake clock is invented.

   fakeClock <- new FakeClock(10:00am)
   handle <- startProcess(fakeClock);
   fakeClock.setTime(10:05am)
   waitForProcess handle
Why not go even further and just pass in a time, not a clock?

   let result = process(start=10:00am, stop=10:05)
Typically my colleagues are pretty accepting of doing the work to fake clocks, but don't generalise that solution to faking other things, or even skipping the fakes, and operating directly on the inputs or outputs.

Does your algorithm need to upload a file to S3? No it doesn't, it needs to produce some bytes and a url where those bytes should go. That can be done in unit-test land without any IO or even a mocking framework. Then some trivial one-liner higher up the call-chain can call your algorithm and do the real S3 upload.


I completely agree, but I still question the purpose of FP languages. Writing the S3 upload code is quite hard, if you really want to handle all possible error scenarios. Even if you use whatever library for that, you still need to know about which errors can it trigger and which need to be handle, and how to handle them. The mental work can be equal to the core function for generating the file. In any language, I'd separate these two pieces of code, but I'm not sure if I'd want to handle S3 upload logic with all the error handling in a FP language. That said, I've not used Clojure yet and that seems like a very pragmatic language, which might be actually usable even for these parts of the code.




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

Search: