Hacker News new | ask | show | jobs
by sbergot 4151 days ago
You are right. In this case effects are not isolated. But in this particular script, there are no interesting things to move into a pure function. It does not mean that it wouldn't be the case in a more complex script.

Like everything, you have to learn to balance your IO code and your pure code. A bit like learning when to factor something into a separate class, or leave it in a few statement/methods. If you write everything in IO & do notation, you don't get the main benefits of haskell. But if your code is more than 10 lines long, chances are that there will be useful pure functions in it.

1 comments

I agree about the benefits of isolating side effects and IO - I generally code in python, and my code tends to look like:

    def main_function(args):
        data = get_data(args)
        result = do_calculations(data)
        push_results(result, args)
Where the function do_calculations is somewhat pure - no side effects, but I do use local variables that I modify inside the function.

> You are right. In this case effects are not isolated. But in this particular script, there are no interesting things to move into a pure function. It does not mean that it wouldn't be the case in a more complex script.

Well, I thought that the point of Haskell (of one of its points) is that it forces the programmer to declare whatever side effect in the type of the function. But here, there is no way to know that main, on top of printing stuff, also messes up with the directory and there is no type signature indicating it - in this example it's no big deal but I could write something like:

    main = do
        rm "/"
        sleep 1
        die "Oooops my files!"
You're right that Haskell doesn't distinguish different IO actions other than by the type they return. There are certainly libraries that do this though, although they aren't widely used.

Even though Haskell doesn't distinguish different classes of IO actions, it still distinguishes IO actions from other kinds of actions (such as stateful actions as per your example), and pure computations and that provides a hell of a lot of bang for buck.

The Idris language has the notion of effect types [1] to make achieving the goal of categorising the kinds of effects being used in a function easier to deal with, but that uses the dependent capabilities of the language.

[1] http://eb.host.cs.st-andrews.ac.uk/drafts/eff-tutorial.pdf

> Not widely used...

I use them in every single application I write, or I make my own tighter, more specific ones. They're incredibly useful in real world apps.

Sorry Tel, I didn't mean to imply that nobody uses them, more that I would guess that they are used less than 1% of the time where their inclusion could be beneficial.
Ha, no offense. I just wanted to emphasize that they are used.

In particular, I think they're more useful in applications than libraries and most Haskell code you can find in the wild is library code---so you end up not seeing them much.

`main` is the entry point of the program. Its type is `IO ()`. It is a warning to omit a type signature in a top level definition, so in a normal program you would have a `main :: IO ()` type definition. The `IO` allows any kind of effect.
Note that style of Pyhton uses block/strict IO (not streaming/lazy) which makes it rather inefficient if any part of he process exits early (due to error or because the user only wanted the first line of output). Most common command line programs (and simple Haskell programs) are streaming not block.