Reputation: 526
I am trying to develop a chat server using Haskell.
There are a lot of useful tools like TChan
, TSkiplist
, forkIO
...etc, but it turns out that most of my code is written inside the IO monads and unsafePerformIO, which sounds very inefficient.
Is it ok to do this, or is haskell not the right tool for this purpose?
Upvotes: 8
Views: 1059
Reputation: 32455
As a general rule, try to first write code as just pure functions without worrying where the data comes from - just assume it's there.
Next wrap that pure functionality in IO to feed your pure functions data and put the results somewhere. It's OK that there's a lot of this going on in a chat application! The IO monad isn't inefficient at all, it's just that we prefer to keep as much code as we can out of it since that's good design - keep the data crunching apart from the IO. A chat application doesn't do a lot of calculation with the data it gets, so it's OK to have loads of IO code.
I think it's definitely better to stick in the IO monad than use unsafePerformIO, because unsafePerformIO is kind of presenting its result as pure data. I might be tempted to use it to get constants from a configuation file, but I've never actually done so, and there's no point if you're heavily in the IO monad anyway. There's a reason it's called unsafe! Petr Pudlák has good advice in the comment below.
I've heard Haskell's monads described as the best imperative programming language in the world. I could split hairs over that description, but I agree with the sentiment, and yes, stick with Haskell. Haskell is good at at the programming you're using it for.
Upvotes: 19
Reputation: 53665
most of my code is written inside the IO monads
That's fine.
and unsafePerformIO
That's bad! Avoid using unsafePerformIO
like the plague; it should only be used by veteran Haskellers in very specific circumstances.
Is it ok to do this, or is haskell not the right tool for this purpose?
It's OK to write code in the IO monad, but not OK to use unsafePerformIO
. Instead, learn how to compose IO actions using the Monad
interface (do
notation). Learn which function type signatures need to include the IO
type.
Upvotes: 5
Reputation: 1693
Whenever you notice that you have a long function that resides inside the IO monad, it pays off to pause and take a look at the computations that take place. In my experience, it's (almost) always the case that some non-IO related stuff is going on that doesn't need access to input output and can be encapsulated in pure functions.
This has the big advantage that it forces you to find proper abstractions and separate (pure) algorithms from input/output handling. Moreover, it's much easier to verify and test pure functions.
Of course, you will still call these pure functions from within some IO a
function (e.g. main
) but that's perfectly fine.
Upvotes: 12