2

I have no problem with the IO Monad. But I want to understand the followings:

  1. In All/almost Haskell tutorials/ text books they keep saying that getChar is not a pure function, because it can give you a different result. My question is: Who said that this is a function in the first place. Unless you give me the implementation of this function, and I study that implementation, I can't guarantee it is pure. So, where is that implementation?
  2. In All/almost Haskell tutorials/ text books, it's said that, say (IO String) is an action that (When executed) it can give you back a value of type String. This is fine, but who/where this execution is taking place. Of course! The computer is doing this execution. This is OK too. but since I am only a beginner, I hope you forgive me to ask, where is the recipe for this "execution". I would guess it is not written in Haskell. Does this later idea mean that, after all, that a Haskell program is converted into a C-like program, which will eventually be converted into Assembly -> Machine code? If so, where one can find the implementation of the IO stuff in Haskell?

Many thanks

Hassan Shahin
  • 211
  • 1
  • 10
  • 8
    `getChar` is not a function; it's a constant. – melpomene Jan 23 '18 at 22:44
  • Right. But a constant can be represented as a function that ignores its arguments and give you back a specific value? – Hassan Shahin Jan 23 '18 at 22:46
  • 3
    ghc doesn't implement it this way, but you can indeed think of `IO` as assembling an imperative program (in e.g. C or assembler code). Or rather: Your Haskell program runs and creates one big `IO` value (an imperative program) bound to `main`. The Haskell runtime system then takes the value of `main` and executes it. – melpomene Jan 23 '18 at 22:46
  • 2
    No, in Haskell a function is something of type `A -> B` for some types A and B. That is, a function takes exactly one argument. There is no `->` in `getChar`'s type. – melpomene Jan 23 '18 at 22:47
  • So, could the phrase "When executed" mean that taking the user actions into consideration, the ghc compiler figures out how to do this execution? – Hassan Shahin Jan 23 '18 at 23:00
  • 2
    Much as with other programming languages, the implementation of `getChar` ultimately involves some OS syscalls to actually read the char. The "when executed" part you read in some documentation only means that, just because some IO action is returned, that does not mean it is executed. E.g. `length [getChar,getChar]` does not perform any IO. Here you can pretend two IO actions are created but not executed (actually, doe to the laziness, they won't even be created, but that's another issue). – chi Jan 23 '18 at 23:32
  • 2
    If you want to see the source of select `IO` functions - [it's there in plain text](https://hackage.haskell.org/package/base-4.6.0.1/docs/src/GHC-IO-Handle-Text.html#hGetChar). – user2407038 Jan 24 '18 at 00:07
  • Thanks. Yeah, I can see they are using this an extension that refers to C++. hmmm. – Hassan Shahin Jan 24 '18 at 00:16
  • 1
    @HassanShahin There is no C++ involved. `CPP` refers to the C preprocessor, which is merely used to process some configuration macros (for instance, one such macro enables parts of the code depending on the compiler version, for backward compatibility purposes). – duplode Jan 24 '18 at 02:02
  • @chi, the actions in that case won't be created *because they already exist*. `getChar` doesn't need any evaluation. – dfeuer Jan 24 '18 at 04:26
  • "Unless you give me the implementation of this function, and I study that implementation, I can't guarantee it is pure." - actually you can guarantee that all Haskell functions are pure, that's kinda the point of Haskell – user253751 Jan 24 '18 at 04:31

1 Answers1

7

Haskell functions are not the same as computations.

A computation is a piece of imperative code (perhaps written in C or Assembler, and then compiled to machine code, directly executable on a processor), that is by nature effectful and even unrestricted in its effects. That is, once it is ran, a computation may access and alter any memory and perform any operations, such as interacting with keyboard and screen, or even launching missiles.

By contrast, a function in a pure language, such as Haskell, is unable to alter arbitrary memory and launch missiles. It can only alter its own personal section of memory and return a result that is specified in its type.

So, in a sense, Haskell is a language that cannot do anything. Haskell is useless. This was a major problem during the 1990's, until IO was integrated into Haskell.

Now, an IO a value is a link to a separately prepared computation that will, eventually, hopefully, produce a. You will not be able to create an IO a out of pure Haskell functions. All the IO primitives are designed separately, and packaged into GHC. You can then compose these simple computations into less trivial ones, and eventually your program may have any effects you may wish.

One point, though: pure functions are separate from each other, they can only influence each other if you use them together. Computations, on the other hand, may interact with each other freely (as I said, they can generally do anything), and therefore can (and do) accidentally break each other. That's why there are so many bugs in software written in imperative languages! So, in Haskell, computations are kept in IO.

I hope this dispels at least some of your confusion.

Ignat Insarov
  • 4,660
  • 18
  • 37
  • Sure, many thanks. It's my bad. I totally forgot that getChar is ALREADY PREPARED computation. As you know, when introducing a functional language, probably in the Introduction, or in Chapter 1 of a textbook, they refer to pure and impure functions, and to make their point of the benefits of pure functions, they take getChar as an example. When you take a function like square a = a*a (where a is a Int), I (as a beginner) have to ask where are the arguments for getChar. Since they don't provide such an argument, the question then arises "Who said it is a function?". Hence the confusion. – Hassan Shahin Jan 24 '18 at 00:43
  • @HassanShahin Please ask if there is anything that needs further clarification! – Ignat Insarov Jan 24 '18 at 00:54
  • @HassanShahin Also, I do recommend you to watch the video I linked to from my answer. It is the principal creator of Haskell explaining things there. I really love that video. – Ignat Insarov Jan 24 '18 at 00:56
  • Thanks again! You have no idea how many tutorials, Haskell books, videos I have read, watched (including SPJ ones). I even went for Category theory. All is fine, I guess. Sometimes you stumble with vey tiny things that you can't wrap your brain around. This is one of those incidents. Many thanks. – Hassan Shahin Jan 24 '18 at 00:58
  • There was a time before Haskell had IO? What was it even useful for? – Qwertie Jan 24 '18 at 01:25
  • 2
    @Qwertie Haskell was founded around 1987, and gained IO around 1997. Before that, there was a more ad-hoc solution for interacting with the real world, somewhat similar to the modern `interact` Prelude function. See also [this answer](https://stackoverflow.com/q/17002119/2108477). – Ignat Insarov Jan 24 '18 at 01:30
  • 2
    @Qwertie Mathematics has no IO either, and yet it is quite useful indeed for reasoning about computation. In much the same way Haskell was developing as a way to represent computation. It was "a bit embarrassing" to be lacking any IO functionality, but it was a tolerable failing for a research language that was exploring new ideas. – amalloy Jan 24 '18 at 05:46