IO inside: Difference between revisions
m (>_< ...nomenclature again!) |
(Now more implementation-independent: I/O in MicroHs doesn't use "worlds") |
||
(25 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
''Haskell I/O can be a source of confusion and surprises for new Haskellers - if that's you, a good place to start is the [[Introduction to IO]] which can help you learn the basics (e.g. the syntax of I/O expressions) before continuing on.'' | ''Haskell I/O can be a source of confusion and surprises for new Haskellers - | ||
if that's you, a good place to start is the [[Introduction to IO]] which can | |||
help you learn the basics (e.g. the syntax of I/O expressions) before | |||
continuing on.'' | |||
While simple I/O code in Haskell looks very similar to its equivalents in imperative languages, attempts to write somewhat more complex code often result in a total mess. This is because Haskell I/O is really very different in how it actually works. | While simple I/O code in Haskell looks very similar to its equivalents in | ||
imperative languages, attempts to write somewhat more complex code often | |||
result in a total mess. This is because Haskell I/O is really very different | |||
in how it actually works. | |||
The following text is an attempt to explain the | The following text is an attempt to explain the inner workings of I/O in | ||
Haskell. This explanation should help you eventually learn all the | |||
smart I/O tips. Moreover, I've added a detailed explanation of various traps | |||
you might encounter along the way. After reading this text, you will be well | |||
on your way towards mastering I/O in Haskell. | |||
== Haskell is a pure language == | == Haskell is a pure language == | ||
Haskell is a pure language and even the I/O system can't break this purity. Being pure means that the result of any function call is fully determined by its arguments. Imperative routines like <code>rand()</code> or <code>getchar()</code> in C, which return different results on each call, are simply impossible to write in Haskell. Moreover, Haskell functions can't have side effects, which means that they can't make any changes "outside the Haskell program", like changing files, writing to the screen, printing, sending data over the network, and so on. These two restrictions together mean that any function call can be replaced by the result of a previous call with the same parameters, and the language ''guarantees'' that all these rearrangements will not change the program result! | Haskell is a pure language and even the I/O system can't break this purity. | ||
Being pure means that the result of any function call is fully determined by | |||
its arguments. Imperative routines like <code>rand()</code> or | |||
<code>getchar()</code> in C, which return different results on each call, are | |||
simply impossible to write in Haskell. Moreover, Haskell functions can't have | |||
side effects, which means that they can't make any changes "outside the Haskell | |||
program", like changing files, writing to the screen, printing, sending data | |||
over the network, and so on. These two restrictions together mean that any | |||
function call can be replaced by the result of a previous call with the same | |||
parameters, and the language ''guarantees'' that all these rearrangements will | |||
not change the program result! For example, the hyperbolic cosine function | |||
<code>cosh</code> can be defined in Haskell as: | |||
<haskell> | <haskell> | ||
cosh r = (exp r + 1/exp r)/2 | |||
</haskell> | </haskell> | ||
using identical calls to <code>exp</code>, which is another function. So | |||
<code>cosh</code> can instead call <code>exp</code> once, and reuse the result: | |||
<haskell> | <haskell> | ||
cosh r = (x + 1/x)/2 where x = exp r | |||
</haskell> | </haskell> | ||
Let's compare this to C: optimizing C compilers try to guess which routines | |||
have no side effects and don't depend on mutable global variables. If this | |||
guess is wrong, an optimization can change the program's semantics! To avoid | |||
this kind of disaster, C optimizers are conservative in their guesses or | |||
require hints from the programmer about the purity of routines. | |||
Compared to an optimizing C compiler, a Haskell compiler is a set of pure | |||
mathematical transformations. This results in much better high-level | |||
optimization facilities. Moreover, pure mathematical computations can be much | |||
more easily divided into several threads that may be executed in parallel, | |||
which is increasingly important in these days of multi-core CPUs. Finally, pure | |||
computations are less error-prone and easier to verify, which adds to Haskell's | |||
robustness and to the speed of program development using Haskell. | |||
Haskell's purity allows the compiler to call only functions whose results are | |||
really required to calculate the final value of a top-level definition (e.g. | |||
<code>main</code>) - this is called lazy evaluation. It's a great thing for | |||
pure mathematical computations, but how about I/O actions? Something like | |||
<haskell> | <haskell> | ||
putStrLn "Press any key to begin formatting" | |||
</haskell> | </haskell> | ||
can't return any meaningful result value, so how can we ensure that the | |||
compiler will not omit or reorder its execution? And in general: How we can | |||
work with stateful algorithms and side effects in an entirely lazy language? | |||
This question has had many different solutions proposed while Haskell was | |||
developed (see [[History of Haskell|A History of Haskell]]), with one | |||
solution eventually making its way into the current standard. | |||
== I/O in Haskell, simplified == | |||
So what is actually inside an I/O action? Let's look at how | |||
[https://github.com/augustss/MicroHs MicroHs] defines the I/O type: | |||
<haskell> | <haskell> | ||
data IO a | |||
</haskell> | </haskell> | ||
just as described on page 95 of 329 in the Haskell 2010 | |||
[https://www.haskell.org/definition/haskell2010.pdf Report]: <i>no visible | |||
data constructors.</i> So someone who is implementing Haskell could in fact | |||
define functions and I/O actions in much the same way. The only difference | |||
that really matters is this: | |||
* Only I/O actions are allowed to make changes "outside the Haskell program". | |||
(Or to state it more formally: only I/O actions are allowed to have externally | |||
visible side effects). | |||
It doesn't get much simpler than that <code>:-D</code> | |||
=== The question of purity === | |||
So if Haskell uses the same side effects for I/O as an imperative language, | |||
how can it possibly be "pure"? | |||
Because of what doesn't work in Haskell: | |||
<haskell> | :<haskell> | ||
\msg x -> seq (putStrLn msg) x | |||
</haskell> | </haskell> | ||
No, that won't work. And neither will this: | |||
<haskell> | :<haskell> | ||
getChar >>= \c -> c | |||
</haskell> | </haskell> | ||
Remember, Haskell functions can't have side effects - they can't make any | |||
changes "outside the Haskell program". Therefore if either of these examples | |||
really did work, then they would no longer be Haskell functions! | |||
(More importantly, just imagine if those two were being used in parallel | |||
somewhere in a program...) | |||
So in Haskell, the result of running an I/O action must be another I/O action. | |||
This restriction ensures that Haskell functions really are [[pure]]. | |||
== Running with I/O == | |||
So, <code>main</code> just has the type <code>IO ()</code>. Let's look at | |||
<code>main</code> calling <code>getChar</code> two times: | |||
<haskell> | <haskell> | ||
main :: IO () | |||
main = getChar >>= \a -> | |||
getChar >>= \b -> | |||
return () | |||
</haskell> | </haskell> | ||
By defining a <code>Monad</code> instance for <code>IO a</code>: | |||
<haskell> | <haskell> | ||
unitIO :: a -> IO a -- implemented | |||
bindIO :: IO a -> (a -> IO b) -> IO b -- elsewhere | |||
instance Monad IO where | instance Monad IO where | ||
return = unitIO | |||
(>>=) = bindIO | |||
</haskell> | </haskell> | ||
we can | we can then expand <code>main</code> to get: | ||
<haskell> | <haskell> | ||
main = getChar `bindIO` (\a -> | |||
getChar `bindIO` (\b -> | |||
unitIO ())) | |||
</haskell> | </haskell> | ||
Now to run <code>main</code>: | |||
# <code>main = getChar `bindIO` (\a -> ...)</code> doesn't require evaluation, continuing; | |||
# run <code>getChar</code> to obtain a character <code>c1 :: Char</code>; | |||
# apply <code>(\a -> ...)</code> to <code>c1</code>; | |||
# then evaluate the result to obtain the next action <code>getChar `bindIO` (\b -> ...)</code>; | |||
# run <code>getChar</code> to obtain another character <code>c2 :: Char</code>; | |||
# apply <code>(\b -> ...)</code> to <code>c2</code>; | |||
# then evaluate the result to obtain the next action <code>unitIO ()</code>; | |||
# run <code>unitIO ()</code> to obtain <code>() :: ()</code>, which ends the program. | |||
From that example we can see that: | |||
* Each action is run - it doesn't matter if what's obtained from running it isn't actually used. | |||
* Each action is run in the order it appears in the program - there is no reordering of actions. | |||
* Each action is run once, then the next action is obtained or the program ends - if a program only uses an action once, then it is only run once. | |||
Overall, in order to obtain the final value of <code>main</code>, each I/O | |||
action that is called from <code>main</code> - directly or indirectly - is | |||
run. This means that each action inserted in the chain will be performed | |||
just at the moment (relative to the other I/O actions) when we intended it | |||
to be called. Let's consider the following program: | |||
<haskell> | <haskell> | ||
Line 281: | Line 188: | ||
</haskell> | </haskell> | ||
Now you have enough knowledge to rewrite it in a low-level way and check that each operation that should be performed will really be performed with the arguments it should have and in the order we expect. | Now you have enough knowledge to rewrite it in a low-level way and check that | ||
each operation that should be performed will really be performed with the | |||
arguments it should have and in the order we expect. | |||
But what about conditional execution? No problem. Let's define the well-known <code>when</code> | But what about conditional execution? No problem. Let's define the well-known | ||
<code>when</code> function: | |||
<haskell> | <haskell> | ||
Line 293: | Line 203: | ||
</haskell> | </haskell> | ||
Because it's a function: | |||
* it will be applied to two arguments; | |||
* its result (the conditional expression) will be evaluated; | |||
* then the chosen action will be run. | |||
As you can see, we can easily include or exclude from the execution chain I/O actions depending on the data values. If <code>condition</code> will be <code>False</code> on the call of <code>when</code>, <code>action</code> will never be | As you can see, we can easily include or exclude from the execution chain I/O | ||
actions depending on the data values. If <code>condition</code> will be | |||
<code>False</code> on the call of <code>when</code>, <code>action</code> will | |||
never be run. | |||
Loops and more complex control structures can be implemented in the same way. | |||
Try it as an exercise! | |||
== <code>(>>=)</code> and <code>do</code> notation == | == <code>(>>=)</code> and <code>do</code> notation == | ||
All beginners (including me) start by thinking that <code>do</code> is some super-awesome statement that executes I/O actions. That's wrong - <code>do</code> is just syntactic sugar that simplifies the writing of definitions that use I/O (and also other monads, but that's beyond the scope of this | All beginners (including me) start by thinking that <code>do</code> is some | ||
super-awesome statement that executes I/O actions. That's wrong - <code>do</code> | |||
is just syntactic sugar that simplifies the writing of definitions that use I/O | |||
(and also other monads, but that's beyond the scope of this manual). <code>do</code> | |||
notation eventually gets translated to a series of I/O actions much like we've | |||
manually written above. This simplifies the gluing of several | |||
I/O actions together. You don't need to use <code>do</code> for just one | |||
action; for example, | |||
<haskell> | <haskell> | ||
Line 323: | Line 238: | ||
</haskell> | </haskell> | ||
Let's examine how to desugar a <code>do</code>-expression with multiple actions in the following example: | Let's examine how to desugar a <code>do</code>-expression with multiple actions | ||
in the following example: | |||
<haskell> | <haskell> | ||
Line 331: | Line 247: | ||
</haskell> | </haskell> | ||
The <code>do</code>-expression here just joins several I/O actions that should be performed sequentially. It's translated to sequential applications of one of the so-called "binding operators", namely <code>(>>)</code>: | The <code>do</code>-expression here just joins several I/O actions that should | ||
be performed sequentially. It's translated to sequential applications of one | |||
of the so-called "binding operators", namely <code>(>>)</code>: | |||
<haskell> | <haskell> | ||
Line 347: | Line 265: | ||
</haskell> | </haskell> | ||
Now you can substitute the definition of <code>(>>)</code> at the places of | |||
its usage and check that program constructed by the <code>do</code> desugaring | |||
is actually the same as we could write by using I/O actions manually. | |||
Now you can substitute the definition of <code>(>>)</code> at the places of its usage and check that program constructed by the <code>do</code> desugaring is actually the same as we could write by manually | |||
A more complex example involves the binding of variables using <code><-</code>: | A more complex example involves the binding of variables using <code><-</code>: | ||
Line 382: | Line 283: | ||
</haskell> | </haskell> | ||
where <code>(>>=)</code> corresponds to | where <code>(>>=)</code> corresponds to <code>bindIO</code>. | ||
As you now know, the <code>(>>)</code> binding operator silently ignores | |||
the value of its first action and returns as an overall result the result of | |||
</ | its second action only. On the other hand, the <code>(>>=)</code> binding | ||
operator (note the extra <code>=</code> at the end) allows us to use the result | |||
of its first action - it gets passed as an additional parameter to the second | |||
one! | |||
You can use <code>(>>)</code> and <code>(>>=)</code> to simplify your program. | |||
For example, in the code above we don't need to introduce the variable, because | |||
the result of running <code>readLn</code> can be passed directly to | |||
<code>print</code>: | |||
:<haskell> | :<haskell> | ||
Line 412: | Line 308: | ||
</haskell> | </haskell> | ||
where <code>action1</code> has type <code>IO a</code> and <code>action2</code> has type <code>IO b</code>, translates into: | where <code>action1</code> has type <code>IO a</code> and <code>action2</code> | ||
has type <span style="white-space: nowrap"><code>IO b</code></span>, translates | |||
into: | |||
<haskell> | <haskell> | ||
Line 418: | Line 316: | ||
</haskell> | </haskell> | ||
where the second argument of <code>(>>=)</code> has the type <code>a -> IO b</code>. It's the way the <code><-</code> binding is processed - the name on the left-hand side of <code><-</code> just becomes a parameter of subsequent operations represented as one large I/O action. Note also that if <code>action1</code> has type <code>IO a</code> then <code>x</code> will just have type <code>a</code>; you can think of the effect of <code><-</code> as "unpacking" the I/O value of <code>action1</code> into <code>x</code>. | where the second argument of <code>(>>=)</code> has the type | ||
<span style="white-space: nowrap"><code>a -> IO b</code></span>. It's the way | |||
the <code><-</code> binding is processed - the name on the left-hand side of | |||
<code><-</code> just becomes a parameter of subsequent operations represented | |||
as one large I/O action. Note also that if <code>action1</code> has type | |||
<span style="white-space: nowrap"><code>IO a</code></span> then <code>x</code> | |||
will just have type <code>a</code>; you can think of the effect of <code><-</code> | |||
as "unpacking" the I/O value of <code>action1</code> into <code>x</code>. | |||
Note also that <code><-</code> is not a true operator; it's pure syntax, just | |||
like <code>do</code> itself. Its meaning results only from the way it gets | |||
desugared. | |||
Look at the next example: | Look at the next example: | ||
Line 440: | Line 348: | ||
</haskell> | </haskell> | ||
I omitted the parentheses here; both the <code>(>>)</code> and the <code>(>>=)</code> operators are left-associative, but lambda-bindings always stretches as far to the right as possible, which means that the <code>a</code> and <code>b</code> bindings introduced here are valid for all remaining actions. As an exercise, add the parentheses yourself and translate this definition into | I omitted the parentheses here; both the <code>(>>)</code> and the | ||
<code>(>>=)</code> operators are left-associative, but lambda-bindings | |||
always stretches as far to the right as possible, which means that the | |||
<code>a</code> and <code>b</code> bindings introduced here are valid for all | |||
remaining actions. As an exercise, add the parentheses yourself and translate | |||
this definition into action-level code. I | |||
think it should be enough to help you finally realize how the <code>do</code> | |||
translation and binding operators work. | |||
Oh, no! I forgot the third monadic operator | Oh, no! I forgot the third monadic operator: <code>return</code>. But that's | ||
understandable - it does very little! The resulting I/O action immediately | |||
< | <i>returns</i> its given argument (when it is run). | ||
</ | |||
How about translating a simple example of <code>return</code> usage? Say, | How about translating a simple example of <code>return</code> usage? Say, | ||
Line 455: | Line 368: | ||
</haskell> | </haskell> | ||
Programmers with an imperative language background often think that <code>return</code> in Haskell, as in other languages, immediately returns from the I/O definition. As you can see in its definition (and even just from its type!), such an assumption is totally wrong. The only purpose of using <code>return</code> is to "lift" some value (of type <code>a</code>) into the result of a whole action (of type <code>IO a</code>) and therefore it should generally be used only as the last executed action of some I/O sequence. For example try to translate the following definition into the corresponding low-level code: | Programmers with an imperative language background often think that | ||
<code>return</code> in Haskell, as in other languages, immediately returns | |||
from the I/O definition. As you can see in its definition (and even just from | |||
its type!), such an assumption is totally wrong. The only purpose of using | |||
<code>return</code> is to "lift" some value (of type <code>a</code>) into the | |||
result of a whole action (of type <code>IO a</code>) and therefore it should | |||
generally be used only as the last executed action of some I/O sequence. For | |||
example try to translate the following definition into the corresponding | |||
low-level code: | |||
<haskell> | <haskell> | ||
Line 464: | Line 385: | ||
</haskell> | </haskell> | ||
and you will realize that the <code>print</code> call is executed even for non-negative values of <code>a</code>. If you need to escape from the middle of an I/O definition, you can use an <code>if</code> expression: | and you will realize that the <code>print</code> call is executed even for | ||
non-negative values of <code>a</code>. If you need to escape from the middle | |||
of an I/O definition, you can use an <code>if</code> expression: | |||
<haskell> | <haskell> | ||
Line 483: | Line 406: | ||
</haskell> | </haskell> | ||
that may be useful for escaping from the middle of a longish <code>do</code>-expression. | that may be useful for escaping from the middle of a longish | ||
<code>do</code>-expression. | |||
Last exercise: implement a function <code>liftM</code> that lifts operations on plain values to the operations on monadic ones. Its type signature: | Last exercise: implement a function <code>liftM</code> that lifts operations | ||
on plain values to the operations on monadic ones. Its type signature: | |||
<haskell> | <haskell> | ||
Line 491: | Line 416: | ||
</haskell> | </haskell> | ||
If that's too hard for you, start with the following high-level definition and rewrite it in low-level fashion: | If that's too hard for you, start with the following high-level definition and | ||
rewrite it in low-level fashion: | |||
<haskell> | <haskell> | ||
Line 501: | Line 427: | ||
== Mutable data (references, arrays, hash tables...) == | == Mutable data (references, arrays, hash tables...) == | ||
As you should know, every name in Haskell is bound to one fixed (immutable) value. This greatly simplifies understanding algorithms and code optimization, but it's inappropriate in some cases. As we all know, there are plenty of algorithms that are simpler to implement in terms of updatable variables, arrays and so on. This means that the value associated with a variable, for example, can be different at different execution points, so reading its value can't be considered as a pure function. Imagine, for example, the following code: | As you should know, every name in Haskell is bound to one fixed (immutable) | ||
value. This greatly simplifies understanding algorithms and code optimization, | |||
but it's inappropriate in some cases. As we all know, there are plenty of | |||
algorithms that are simpler to implement in terms of updatable variables, | |||
arrays and so on. This means that the value associated with a variable, for | |||
example, can be different at different execution points, so reading its value | |||
can't be considered as a pure function. Imagine, for example, the following | |||
code: | |||
<haskell> | <haskell> | ||
Line 515: | Line 448: | ||
# These three calls may be rearranged in any order because they appear to be independent of each other. | # These three calls may be rearranged in any order because they appear to be independent of each other. | ||
This is obviously not what was intended. What's the solution? You already know this - use I/O actions! Doing that guarantees: | This is obviously not what was intended. What's the solution? You already know | ||
this - use I/O actions! Doing that guarantees: | |||
# the result of the "same" action (such as <code>readVariable varA</code>) will not be reused | # the result of the "same" action (such as <span style="white-space: nowrap"><code>readVariable varA</code></span>) will not be reused | ||
# each action will have to be executed | # each action will have to be executed | ||
# the execution order will be retained as written | # the execution order will be retained as written | ||
Line 532: | Line 466: | ||
</haskell> | </haskell> | ||
Here, <code>varA</code> has the type <code>IORef Int</code> which means "a variable (reference) in the I/O monad holding a value of type <code>Int</code>". <code>newIORef</code> creates a new variable (reference) and returns it, and then read/write actions use this reference. The value returned by the <code>readIORef varA</code> action depends not only on the variable involved but also on the moment this operation is performed so it can return different values on each call. | Here, <code>varA</code> has the type <span style="white-space: nowrap"><code>IORef Int</code></span> | ||
which means "a variable (reference) in the I/O monad holding a value of type | |||
<code>Int</code>". <code>newIORef</code> creates a new variable (reference) | |||
and returns it, and then read/write actions use this reference. The value | |||
returned by the <span style="white-space: nowrap"><code>readIORef varA</code></span> | |||
action depends not only on the variable involved but also on the moment this | |||
operation is performed so it can return different values on each call. | |||
Arrays, hash tables and any other | Arrays, hash tables and any other ''mutable'' data structures are defined in | ||
the same way - for each of them, there's an operation that creates new "mutable | |||
values" and returns a reference to it. Then value-specific read and write | |||
operations in the I/O monad are used. The following code shows an example using | |||
mutable arrays: | |||
<haskell> | <haskell> | ||
Line 545: | Line 489: | ||
</haskell> | </haskell> | ||
Here, an array of 10 elements with 37 as the initial value at each location is created. After reading the value of the first element (index 1) into <code>a</code> this element's value is changed to 64 and then read again into <code>b</code>. As you can see by executing this code, <code>a</code> will be set to 37 and <code>b</code> to 64. | Here, an array of 10 elements with 37 as the initial value at each location is | ||
created. After reading the value of the first element (index 1) into | |||
<code>a</code> this element's value is changed to 64 and then read again into | |||
<code>b</code>. As you can see by executing this code, <code>a</code> will be | |||
set to 37 and <code>b</code> to 64. | |||
Other state-dependent operations are also often implemented with I/O actions. For example, a random number generator should return a different value on each call. It looks natural to give it a type involving <code>IO</code>: | Other state-dependent operations are also often implemented with I/O actions. | ||
For example, a random number generator should return a different value on each | |||
call. It looks natural to give it a type involving <code>IO</code>: | |||
<haskell> | <haskell> | ||
Line 553: | Line 503: | ||
</haskell> | </haskell> | ||
Moreover, when you import a C routine you should be careful - if this routine is impure, i.e. its result depends on something "outside the Haskell program" (file system, memory contents, its own <code>static</code> internal state and so on), you should give it an <code>IO</code> type. Otherwise, the compiler can "optimize" repetitive calls to the definition with the same parameters! | Moreover, when you import a C routine you should be careful - if this routine | ||
is impure, i.e. its result depends on something "outside the Haskell program" | |||
(file system, memory contents, its own <code>static</code> internal state and | |||
so on), you should give it an <code>IO</code> type. Otherwise, the compiler | |||
can "optimize" repetitive calls to the definition with the same parameters! | |||
For example, we can write a non-<code>IO</code> type for: | For example, we can write a non-<code>IO</code> type for: | ||
Line 569: | Line 523: | ||
</haskell> | </haskell> | ||
If you will declare <code>tell</code> as a pure function (without <code>IO</code>) then you may get the same position on each call! | If you will declare <code>tell</code> as a pure function (without | ||
<code>IO</code>) then you may get the same position on each call! | |||
=== Encapsulated mutable data: ST === | === Encapsulated mutable data: ST === | ||
If you're going to be doing things like sending text to a screen or reading data from a scanner, <code>IO</code> is the type to start with - you can then customise | If you're going to be doing things like sending text to a screen or reading | ||
data from a scanner, <code>IO</code> is the type to start with - you can then | |||
customise existing I/O operations or add new ones as you see fit. But what if | |||
that shiny-new (or classic) algorithm you're working on really only needs | |||
mutable state - then having to drag that <code>IO</code> type from | |||
<code>main</code> all the way through to wherever you're implementing the | |||
algorithm can get quite irritating. | |||
Fortunately there is a better way! One that remains totally pure and yet allows the use of references, arrays, and so on - and it's done using, you guessed it, Haskell's versatile type system (and one extension). | Fortunately there is a better way! One that remains totally pure and yet | ||
allows the use of references, arrays, and so on - and it's done using, you | |||
guessed it, Haskell's versatile type system (and one extension). | |||
Remember our definition of <code>IO</code>? | Remember our definition of <code>IO</code>? | ||
<haskell> | <haskell> | ||
data IO a | |||
</haskell> | </haskell> | ||
Well, the new <code>ST</code> type makes just one change: | Well, the new <code>ST</code> type makes just one change - in theory, it can | ||
be used with any suitable state type: | |||
<haskell> | <haskell> | ||
data ST s a | |||
</haskell> | </haskell> | ||
If we wanted to, we could use <code>ST</code> to define <code>IO</code>: | If we wanted to, we could even use <code>ST</code> to define <code>IO</code>: | ||
<haskell> | <haskell> | ||
type IO a = ST RealWorld a | type IO a = ST RealWorld a -- RealWorld defined elsewhere | ||
</haskell> | </haskell> | ||
Line 598: | Line 562: | ||
<haskell> | <haskell> | ||
newSTRef :: a -> ST s (STRef s a) -- these are | newSTRef :: a -> ST s (STRef s a) -- these are | ||
readSTRef :: STRef s a -> ST s a -- usually | readSTRef :: STRef s a -> ST s a -- usually | ||
Line 606: | Line 568: | ||
newSTArray :: Ix i => (i, i) -> ST s (STArray s i e) -- also usually primitive | newSTArray :: Ix i => (i, i) -> ST s (STArray s i e) -- also usually primitive | ||
⋮ | ⋮ | ||
unitST :: a -> ST s a | |||
bindST :: ST s a -> (a -> ST s b) -> ST s b | |||
instance Monad (ST s) where | |||
return = unitST | |||
(>>=) = bindST | |||
</haskell> | </haskell> | ||
...that's right - this new <code>ST</code> type is also monadic! | ...that's right - this new <code>ST</code> type is also monadic! | ||
So what's the big difference between the <code>ST</code> and <code>IO</code> types? In one word - <code>runST</code>: | So what's the big difference between the <code>ST</code> and <code>IO</code> | ||
types? In one word - <code>runST</code>: | |||
<haskell> | <haskell> | ||
runST :: (forall s . ST s a) -> a | runST :: (forall s . ST s a) -> a | ||
</haskell> | </haskell> | ||
Yes - it has a very unusual type. But that type allows you to run your stateful computation ''as if it was a pure definition!'' | Yes - it has a very unusual type. But that type allows you to run your | ||
stateful computation ''as if it was a pure definition!'' | |||
The <code>s</code> type variable in <code>ST</code> is the type of the local state. Moreover, all the fun mutable stuff available for <code>ST</code> is quantified over <code>s</code>: | The <code>s</code> type variable in <code>ST</code> is the type of the local | ||
state. Moreover, all the fun mutable stuff available for <code>ST</code> is | |||
quantified over <code>s</code>: | |||
<haskell> | <haskell> | ||
newSTRef :: a -> ST s (STRef s a) | newSTRef :: a -> ST s (STRef s a) | ||
newArray_ :: Ix i => (i, i) -> ST s (STArray s i e) | newArray_ :: Ix i => (i, i) -> ST s (STArray s i e) | ||
</haskell> | </haskell> | ||
So why does <code>runST</code> have such a funky type? Let's see what would happen if we wrote | So why does <code>runST</code> have such a funky type? Let's see what would | ||
happen if we wrote | |||
<haskell> | <haskell> | ||
makeSTRef :: a -> STRef s a | makeSTRef :: a -> STRef s a | ||
makeSTRef a = runST (newSTRef a) | makeSTRef a = runST (newSTRef a) | ||
</haskell> | </haskell> | ||
This fails, because <code>newSTRef a</code> doesn't work for all state types <code>s</code> - it only works for the <code>s</code> from the return type< | This fails, because <code>newSTRef a</code> doesn't work for all state types | ||
<code>s</code> - it only works for the <code>s</code> from the return type | |||
<span style="white-space: nowrap"><code>STRef s a</code></span>. | |||
This is all sort of wacky, but the result is that you can only run an <code>ST</code> computation where the output type is functionally pure, and makes no references to the internal mutable state of the computation. In exchange for that, there's no access to I/O operations like writing to or reading from the console | This is all sort of wacky, but the result is that you can only run an | ||
<code>ST</code> computation where the output type is functionally pure, and | |||
makes no references to the internal mutable state of the computation. In | |||
exchange for that, there's no access to I/O operations like writing to or | |||
reading from the console. The monadic <code>ST</code> type only has references, | |||
arrays, and such that are useful for performing pure computations. | |||
Due to how similar <code>IO</code> and <code>ST</code> are internally, there's | |||
this function: | |||
<haskell> | <haskell> | ||
Line 650: | Line 619: | ||
</haskell> | </haskell> | ||
The difference is that <code>ST</code> uses the type system to forbid unsafe behavior like extracting mutable objects from their safe <code>ST</code> wrapping, but allowing purely functional outputs to be performed with all the handy access to mutable references and arrays. | The difference is that <code>ST</code> uses the type system to forbid unsafe | ||
behavior like extracting mutable objects from their safe <code>ST</code> | |||
wrapping, but allowing purely functional outputs to be performed with all the | |||
handy access to mutable references and arrays. | |||
For example, here's a particularly convoluted way to compute the integer that comes after zero: | For example, here's a particularly convoluted way to compute the integer that | ||
comes after zero: | |||
<haskell> | <haskell> | ||
Line 667: | Line 640: | ||
== I/O actions as values == | == I/O actions as values == | ||
By this point you should understand why it's impossible to use I/O actions inside non-I/O (pure) functions | By this point you should understand why it's impossible to use I/O actions | ||
inside non-I/O (pure) functions: when needed, fully-applied functions are | |||
always evaluated - they aren't run like I/O actions. In addition, the | |||
prohibition of using I/O actions inside pure functions is maintained by the | |||
type system (as it usually is in Haskell). | |||
But while pure code can't be used to run I/O actions, it can work with them as | |||
with any other value - I/O actions can be stored in data structures, passed as | |||
parameters, returned as results, collected in lists or in tuples. But what | |||
won't work is something like: | |||
<haskell> | <haskell> | ||
\ msg x -> case putStrLn msg of _ -> x | |||
</haskell> | </haskell> | ||
because it will be treated as a function, not an I/O action. | |||
To run an I/O action, we need to make it part of <code>main</code>: | |||
* either directly: | |||
:<code>main = action</code> | |||
* or in the "action chain" of another action which is already a part of the <code>main</code> "chain": | |||
:<code>main = ... >>= \ _ -> action >>= ...</code> | |||
Only then will the action be run. For example, in: | |||
<haskell> | <haskell> | ||
main = do let | main = do let skip2chars = getChar >> getChar >> return () | ||
putStr "Press two keys" | putStr "Press two keys" | ||
skip2chars | |||
return () | return () | ||
</haskell> | </haskell> | ||
the non-<code>let</code> actions are run in the exact order in which they're | |||
written. | |||
=== Example: a list of I/O actions === | === Example: a list of I/O actions === | ||
Line 705: | Line 689: | ||
</haskell> | </haskell> | ||
I used additional parentheses around each action, although they aren't really required. If you still can't believe that these actions won't be | I used additional parentheses around each action, although they aren't really | ||
required. If you still can't believe that these actions won't be run | |||
immediately, remember that in this expression: | |||
<haskell> | <haskell> | ||
\ b -> if b then (putStr "started...") (putStrLn "completed.") | |||
</haskell> | </haskell> | ||
Well, now we want to execute some of these actions. No problem, just insert them into the <code>main</code> chain: | both I/O actions won't immediately be run either. | ||
Well, now we want to execute some of these actions. No problem, just insert | |||
them into the <code>main</code> chain: | |||
<haskell> | <haskell> | ||
Line 719: | Line 708: | ||
</haskell> | </haskell> | ||
Looks strange, right? Really, any I/O action that you write in a <code>do</code>-expression (or use as a parameter for the <code>(>>)</code>/<code>(>>=)</code> operators) is an expression returning a result of type <code>IO a</code> for some type <code>a</code>. Typically, you use some function that has the type <code>x -> y -> ... -> IO a</code> and provide all the x, y, etc. parameters. But you're not limited to this standard scenario - don't forget that Haskell is a functional language and you're free to | Looks strange, right? Really, any I/O action that you write in a | ||
<code>do</code>-expression (or use as a parameter for the | |||
<code>(>>)</code>/<code>(>>=)</code> operators) is an expression returning a | |||
result of type <span style="white-space: nowrap"><code>IO a</code></span> for | |||
some type <code>a</code>. Typically, you use some function that has the type | |||
<span style="white-space: nowrap"><code>x -> y -> ... -> IO a</code></span> | |||
and provide all the <code>x</code>, <code>y</code>, etc. parameters. But you're | |||
not limited to this standard scenario - don't forget that Haskell is a | |||
functional language and you're free to evaluate any value as required | |||
(recall that <span style="white-space: nowrap"><code>IO a</code></span> is | |||
really a function type) in any possible way. Here we just extracted several | |||
functions from the list - no problem. This value can also be constructed | |||
on-the-fly, as we've done in the previous example - that's also OK. | |||
Want to see this value passed as a parameter? Just look at the | |||
definition of <code>when</code>. Hey, we can buy, sell, and rent these I/O | |||
actions just like we can with any other values! For example, let's | |||
define a function that executes all the I/O actions in the list: | |||
<haskell> | <haskell> | ||
Line 728: | Line 733: | ||
</haskell> | </haskell> | ||
No mirrors | No smoke or mirrors - we just extract I/O actions from the list and insert | ||
them into a chain of I/O operations that should be performed one after another | |||
(in the same order that they occurred in the list) to obtain the end result | |||
of the entire <code>sequence_</code> call. | |||
With the help of <code>sequence_</code>, we can rewrite our last <code>main</code> action as: | With the help of <code>sequence_</code>, we can rewrite our last <code>main</code> | ||
action as: | |||
<haskell> | <haskell> | ||
Line 736: | Line 745: | ||
</haskell> | </haskell> | ||
Haskell's ability to work with I/O actions | Haskell's ability to work with I/O actions just like other values | ||
allows us to define control structures of arbitrary | |||
complexity. Try, for example, to define a control structure that repeats an | |||
action until it returns the <code>False</code> result: | |||
<haskell> | <haskell> | ||
Line 743: | Line 755: | ||
</haskell> | </haskell> | ||
Most programming languages don't allow you to define control structures at all, and those that do often require you to use a macro-expansion system. In Haskell, control structures are just trivial functions anyone can write. | Most programming languages don't allow you to define control structures at all, | ||
and those that do often require you to use a macro-expansion system. In | |||
Haskell, control structures are just trivial functions anyone can write. | |||
=== Example: returning an I/O action as a result === | === Example: returning an I/O action as a result === | ||
How about returning an I/O action as the result of a function? Well, we've done this for each I/O definition - they all return I/O actions | How about returning an I/O action as the result of a function? Well, we've | ||
done this for each I/O definition - they all return I/O actions built up from | |||
other I/O actions (or themselves, if they're recursive). While we usually just | |||
execute them as part of a | |||
higher-level I/O definition, it's also possible to just collect them without | |||
actual execution: | |||
<haskell> | <haskell> | ||
main = do let a = sequence ioActions | main = do let a = sequence ioActions | ||
b = when True getChar | b = when True getChar | ||
c = getChar >> getChar | c = getChar >> getChar >> return () | ||
putStr "These let-bindings are not executed!" | putStr "These let-bindings are not executed!" | ||
</haskell> | </haskell> | ||
These assigned I/O actions can be used as parameters to other definitions, or written to global variables, or processed in some other way, or just executed later, as we did in the example with <code> | These assigned I/O actions can be used as parameters to other definitions, or | ||
written to global variables, or processed in some other way, or just executed | |||
later, as we did in the example with <code>skip2chars</code>. | |||
But how about returning a parameterized I/O action from an I/O definition? | But how about returning a parameterized I/O action from an I/O definition? | ||
Here's a definition that returns the i'th byte from a file represented as a | |||
Handle: | |||
<haskell> | <haskell> | ||
Line 765: | Line 788: | ||
</haskell> | </haskell> | ||
So far so good. But how about a definition that returns the i'th byte of a file with a given name without reopening it each time? | So far so good. But how about a definition that returns the i'th byte of a | ||
file with a given name without reopening it each time? | |||
<haskell> | <haskell> | ||
Line 773: | Line 797: | ||
</haskell> | </haskell> | ||
As you can see, it's an I/O definition that opens a file and returns...an I/O action that will read the specified byte. But we can go further and include the <code>readi</code> body in <code>readfilei</code>: | As you can see, it's an I/O definition that opens a file and returns...an I/O | ||
action that will read the specified byte. But we can go further and include | |||
the <code>readi</code> body in <code>readfilei</code>: | |||
<haskell> | <haskell> | ||
Line 782: | Line 808: | ||
</haskell> | </haskell> | ||
That's a little better. But why do we add <code>h</code> as a parameter to <code>readi</code> if it can be obtained from the environment where <code>readi</code> is now defined? An even shorter version is this: | That's a little better. But why do we add <code>h</code> as a parameter to | ||
<code>readi</code> if it can be obtained from the environment where <code>readi</code> | |||
is now defined? An even shorter version is this: | |||
<haskell> | <haskell> | ||
Line 791: | Line 819: | ||
</haskell> | </haskell> | ||
What have we done here? We've build a parameterized I/O action involving local names inside <code>readfilei</code> and returned it as the result. Now it can be used in the following way: | What have we done here? We've build a parameterized I/O action involving local | ||
names inside <code>readfilei</code> and returned it as the result. Now it can | |||
be used in the following way: | |||
<haskell> | <haskell> | ||
Line 800: | Line 830: | ||
</haskell> | </haskell> | ||
This way of using I/O actions is very typical for Haskell programs - you just construct one or more I/O actions that you need, with or without parameters, possibly involving the parameters that your "constructor" received, and return them to the caller. Then these I/O actions can be used in the rest of the program without any knowledge | This way of using I/O actions is very typical for Haskell programs - you just | ||
construct one or more I/O actions that you need, with or without parameters, | |||
possibly involving the parameters that your "constructor" received, and return | |||
them to the caller. Then these I/O actions can be used in the rest of the | |||
program without any knowledge of how you actually implemented them. One | |||
thing this can be used for is to partially emulate the OOP (or more precisely, | |||
the ADT) programming paradigm. | |||
=== Example: a memory allocator generator === | === Example: a memory allocator generator === | ||
As an example, one of my programs has a module which is a memory suballocator. It receives the address and size of a large memory block and returns two specialised I/O operations - one to allocate a subblock of a given size and the other to free the allocated subblock: | As an example, one of my programs has a module which is a memory suballocator. | ||
It receives the address and size of a large memory block and returns two | |||
specialised I/O operations - one to allocate a subblock of a given size and the | |||
other to free the allocated subblock: | |||
<haskell> | <haskell> | ||
Line 818: | Line 857: | ||
</haskell> | </haskell> | ||
How this is implemented? <code>alloc</code> and <code>free</code> work with references created inside the <code>memoryAllocator</code> definition. Because the creation of these references is a part of the <code>memoryAllocator</code> I/O-action chain, a new independent set of references will be created for each memory block for which <code>memoryAllocator</code> is called: | How this is implemented? <code>alloc</code> and <code>free</code> work with | ||
references created inside the <code>memoryAllocator</code> definition. Because | |||
the creation of these references is a part of the <code>memoryAllocator</code> | |||
I/O-action chain, a new independent set of references will be created for each | |||
memory block for which <code>memoryAllocator</code> is called: | |||
<haskell> | <haskell> | ||
memoryAllocator buf size = do start <- newIORef buf | memoryAllocator buf size = | ||
do start <- newIORef buf | |||
end <- newIORef (buf `plusPtr` size) | |||
... | |||
</haskell> | </haskell> | ||
These two references are read and written in the <code>alloc</code> and <code>free</code> definitions (we'll implement a very simple memory allocator for this example): | These two references are read and written in the <code>alloc</code> and | ||
<code>free</code> definitions (we'll implement a very simple memory allocator | |||
for this example): | |||
<haskell> | <haskell> | ||
Line 837: | Line 883: | ||
</haskell> | </haskell> | ||
What we've defined here is just a pair of closures that use state available at the moment of their definition. As you can see, it's as easy as in any other functional language, despite Haskell's lack of direct support for impure routines. | What we've defined here is just a pair of closures that use state available at | ||
the moment of their definition. As you can see, it's as easy as in any other | |||
functional language, despite Haskell's lack of direct support for impure | |||
routines. | |||
The following example uses the operations returned by <code>memoryAllocator</code>, to simultaneously allocate/free blocks in two independent memory buffers: | The following example uses the operations returned by <code>memoryAllocator</code>, | ||
to simultaneously allocate/free blocks in two independent memory buffers: | |||
<haskell> | <haskell> | ||
Line 856: | Line 906: | ||
=== Example: emulating OOP with record types === | === Example: emulating OOP with record types === | ||
Let's implement the classical OOP example: drawing figures. There are figures of different types: circles, rectangles and so on. The task is to create a heterogeneous list of figures. All figures in this list should support the same set of operations: draw, move and so on. We will define these operations using I/O actions. Instead of a "class" let's define a structure | Let's implement the classical OOP example: drawing figures. There are figures | ||
of different types: circles, rectangles and so on. The task is to create a | |||
heterogeneous list of figures. All figures in this list should support the same | |||
set of operations: draw, move and so on. We will define these operations using | |||
I/O actions. Instead of a "class" let's define a structure from which all of | |||
the required operations can be accessed: | |||
<haskell> | <haskell> | ||
Line 866: | Line 921: | ||
</haskell> | </haskell> | ||
The constructor of each figure's type should just return a <code>Figure</code> record: | The constructor of each figure's type should just return a <code>Figure</code> | ||
record: | |||
<haskell> | <haskell> | ||
Line 876: | Line 932: | ||
</haskell> | </haskell> | ||
We will "draw" figures by just printing their current parameters. Let's start with | We will "draw" figures by just printing their current parameters. Let's start | ||
with implementing simplified <code>circle</code> and <code>rectangle</code> | |||
constructors, without actual <code>move</code> support: | |||
<haskell> | <haskell> | ||
Line 888: | Line 946: | ||
</haskell> | </haskell> | ||
As you see, each constructor just returns a fixed <code>draw</code> operation that prints parameters with which the concrete figure was created. Let's test it: | As you see, each constructor just returns a fixed <code>draw</code> operation | ||
that prints parameters with which the concrete figure was created. Let's test | |||
it: | |||
<haskell> | <haskell> | ||
Line 902: | Line 962: | ||
</haskell> | </haskell> | ||
Now let's define "full-featured" figures that can actually be moved around. In order to achieve this, we should provide each figure with a mutable variable that holds each figure's current screen location. The type of this variable will be< | Now let's define "full-featured" figures that can actually be moved around. In | ||
order to achieve this, we should provide each figure with a mutable variable | |||
that holds each figure's current screen location. The type of this variable | |||
will be <span style="white-space: nowrap"><code>IORef Point</code></span>. This | |||
variable should be created in the figure constructor and manipulated in I/O | |||
operations (closures) enclosed in the <code>Figure</code> record: | |||
<haskell> | <haskell> | ||
Line 943: | Line 1,008: | ||
</haskell> | </haskell> | ||
It's important to realize that we are not limited to including only I/O actions in a record that's intended to simulate a C++/Java-style interface. The record can also include values, <code>IORef</code>s, pure functions - in short, any type of data. For example, we can easily add to the <code>Figure</code> interface fields for area and origin: | It's important to realize that we are not limited to including only I/O actions | ||
in a record that's intended to simulate a C++/Java-style interface. The record | |||
can also include values, <code>IORef</code>s, pure functions - in short, any | |||
type of data. For example, we can easily add to the <code>Figure</code> | |||
interface fields for area and origin: | |||
<haskell> | <haskell> | ||
Line 956: | Line 1,025: | ||
== Exception handling (under development) == | == Exception handling (under development) == | ||
Although Haskell provides a set of exception raising/handling features comparable to those in popular OOP languages (C++, Java, C#), this part of the language receives much less attention. This is for two reasons: | Although Haskell provides a set of exception raising/handling features | ||
comparable to those in popular OOP languages (C++, Java, C#), this part of the | |||
language receives much less attention. This is for two reasons: | |||
* you just don't need to worry as much about them - most of the time it just works "behind the scenes". | * you just don't need to worry as much about them - most of the time it just works "behind the scenes". | ||
Line 962: | Line 1,033: | ||
* Haskell, lacking OOP-style inheritance, doesn't allow the programmer to easily subclass exception types, therefore limiting the flexibility of exception handling. | * Haskell, lacking OOP-style inheritance, doesn't allow the programmer to easily subclass exception types, therefore limiting the flexibility of exception handling. | ||
Haskell can raise more exceptions than other programming languages - pattern | |||
match failures, calls with invalid arguments (such as | |||
<span style="white-space: nowrap"><code>head []</code></span>) and computations | |||
whose results depend on special values <code>undefined</code> and | |||
<span style="white-space: nowrap"><code>error "...."</code></span> all raise | |||
their own exceptions: | |||
* example 1: | * example 1: | ||
Line 987: | Line 1,063: | ||
== Interfacing with C/C++ and foreign libraries (under development) == | == Interfacing with C/C++ and foreign libraries (under development) == | ||
While Haskell is great at algorithm development, speed isn't its best side. We can combine the best of both languages, though, by writing speed-critical parts of program in C and the rest in Haskell. We just need a way to call C routines from Haskell and vice versa, and to marshal data between the two languages. | While Haskell is great at algorithm development, speed isn't its best side. We | ||
can combine the best of both languages, though, by writing speed-critical parts | |||
of program in C and the rest in Haskell. We just need a way to call C routines | |||
from Haskell and vice versa, and to marshal data between the two languages. | |||
We also need to interact with C to use Windows/Linux APIs, linking to various libraries and DLLs. Even interfacing with other languages often requires going through C, which acts as a "common denominator". [https://www.haskell.org/onlinereport/haskell2010/haskellch8.html Chapter 8 of the Haskell 2010 report] provides a complete description of interfacing with C. | We also need to interact with C to use Windows/Linux APIs, linking to various | ||
libraries and DLLs. Even interfacing with other languages often requires going | |||
through C, which acts as a "common denominator". | |||
[https://www.haskell.org/onlinereport/haskell2010/haskellch8.html Chapter 8 of the Haskell 2010 report] | |||
provides a complete description of interfacing with C. | |||
We will learn to use the FFI via a series of examples. These examples include C/C++ code, so they need C/C++ compilers to be installed, the same will be true if you need to include code written in C/C++ in your program (C/C++ compilers are not required when you just need to link with existing libraries providing APIs with C calling convention). On Unix (and Mac OS?) systems, the system-wide default C/C++ compiler is typically used by GHC installation. On Windows, no default compilers exist, so GHC is typically shipped with a C compiler, and you may find on the download page a GHC distribution bundled with C and C++ compilers. Alternatively, you may find and install a GCC/MinGW version compatible with your GHC installation. | We will learn to use the FFI via a series of examples. These examples include | ||
C/C++ code, so they need C/C++ compilers to be installed, the same will be true | |||
if you need to include code written in C/C++ in your program (C/C++ compilers | |||
are not required when you just need to link with existing libraries providing | |||
APIs with C calling convention). On Unix (and Mac OS?) systems, the system-wide | |||
default C/C++ compiler is typically used by GHC installation. On Windows, no | |||
default compilers exist, so GHC is typically shipped with a C compiler, and you | |||
may find on the download page a GHC distribution bundled with C and C++ | |||
compilers. Alternatively, you may find and install a GCC/MinGW version | |||
compatible with your GHC installation. | |||
If you need to make your C/C++ code as fast as possible, you may compile your code by Intel compilers instead of GCC. However, these compilers are not free, moreover on Windows, code compiled by Intel compilers may not interact correctly with GHC-compiled code, unless one of them is put into DLLs (due to object file incompatibility). | If you need to make your C/C++ code as fast as possible, you may compile your | ||
code by Intel compilers instead of GCC. However, these compilers are not free, | |||
moreover on Windows, code compiled by Intel compilers may not interact | |||
correctly with GHC-compiled code, unless one of them is put into DLLs (due to | |||
object file incompatibility). | |||
[http://www.haskell.org/haskellwiki/Applications_and_libraries/Interfacing_other_languages More links]: | [http://www.haskell.org/haskellwiki/Applications_and_libraries/Interfacing_other_languages More links]: | ||
Line 1,011: | Line 1,107: | ||
=== Foreign calls === | === Foreign calls === | ||
We begin by learning how to call C routines from Haskell and Haskell definitions from C. The first example consists of three files: | We begin by learning how to call C routines from Haskell and Haskell | ||
definitions from C. The first example consists of three files: | |||
''main.hs:'' | ''main.hs:'' | ||
Line 1,050: | Line 1,147: | ||
ghc --make main.hs vile.c | ghc --make main.hs vile.c | ||
Or, you may compile C module(s) separately and link in ".o" files (this may be preferable if you use <code>make</code> and don't want to recompile unchanged sources; ghc's <code>--make</code> option provides smart recompilation only for ".hs" files): | Or, you may compile C module(s) separately and link in ".o" files (this may be | ||
preferable if you use <code>make</code> and don't want to recompile unchanged | |||
sources; ghc's <code>--make</code> option provides smart recompilation only for | |||
".hs" files): | |||
ghc -c vile.c | ghc -c vile.c | ||
ghc --make main.hs vile.o | ghc --make main.hs vile.o | ||
You may use gcc/g++ directly to compile your C/C++ files but I recommend to do linking via ghc because it adds a lot of libraries required for execution of Haskell code. For the same reason, even if <code>main</code> in your program is written in C/C++, I recommend calling it from the Haskell action <code>main</code> - otherwise you'll have to explicitly init/shutdown the GHC RTS (run-time system). | You may use gcc/g++ directly to compile your C/C++ files but I recommend to do | ||
linking via ghc because it adds a lot of libraries required for execution of | |||
Haskell code. For the same reason, even if <code>main</code> in your program is | |||
written in C/C++, I recommend calling it from the Haskell action <code>main</code> - | |||
otherwise you'll have to explicitly init/shutdown the GHC RTS (run-time system). | |||
We use the <code>foreign import</code> declaration to import foreign routines into Haskell, and <code>foreign export</code> to export Haskell definitions "outside" for imperative languages to use. Note that <code>import</code> creates a new Haskell symbol (from the external one), while <code>export</code> uses a Haskell symbol previously defined. Technically speaking, both types of declarations create a wrapper that converts the names and calling conventions from C to Haskell or vice versa. | We use the <code>foreign import</code> declaration to import foreign routines | ||
into Haskell, and <code>foreign export</code> to export Haskell definitions | |||
"outside" for imperative languages to use. Note that <code>import</code> | |||
creates a new Haskell symbol (from the external one), while <code>export</code> | |||
uses a Haskell symbol previously defined. Technically speaking, both types of | |||
declarations create a wrapper that converts the names and calling conventions | |||
from C to Haskell or vice versa. | |||
=== All about the <code>foreign</code> declaration === | === All about the <code>foreign</code> declaration === | ||
The <code>ccall</code> specifier in foreign declarations means the use of the C (not C++ !) calling convention. This means that if you want to write the external routine in C++ (instead of C) you should add <code>export "C"</code> specification to its declaration - otherwise you'll get linking errors. Let's rewrite our first example to use C++ instead of C: | The <code>ccall</code> specifier in foreign declarations means the use of the C | ||
(not C++ !) calling convention. This means that if you want to write the | |||
external routine in C++ (instead of C) you should add <code>export "C"</code> | |||
specification to its declaration - otherwise you'll get linking errors. Let's | |||
rewrite our first example to use C++ instead of C: | |||
''prototypes.h:'' | ''prototypes.h:'' | ||
Line 1,080: | Line 1,194: | ||
ghc --make main.hs vile.cpp | ghc --make main.hs vile.cpp | ||
where "vile.cpp" is just a renamed copy of "vile.c" from the first example. Note that the new "prototypes.h" is written to allow compiling it both as C and C++ code. When it's included from "vile.cpp", it's compiled as C++ code. When GHC compiles "main.hs" via the C compiler (enabled by the <code>-fvia-C</code> option), it also includes "prototypes.h" but compiles it in C mode. It's why you need to specify ".h" files in <code>foreign</code> declarations - depending on which Haskell compiler you use, these files may be included to check consistency of C and Haskell declarations. | where "vile.cpp" is just a renamed copy of "vile.c" from the first example. | ||
Note that the new "prototypes.h" is written to allow compiling it both as C and | |||
C++ code. When it's included from "vile.cpp", it's compiled as C++ code. When | |||
GHC compiles "main.hs" via the C compiler (enabled by the <code>-fvia-C</code> | |||
option), it also includes "prototypes.h" but compiles it in C mode. It's why | |||
you need to specify ".h" files in <code>foreign</code> declarations - depending | |||
on which Haskell compiler you use, these files may be included to check | |||
consistency of C and Haskell declarations. | |||
The quoted part of the foreign declaration may also be used to give the import or export another name - for example, | The quoted part of the foreign declaration may also be used to give the import | ||
or export another name - for example, | |||
<haskell> | <haskell> | ||
Line 1,098: | Line 1,220: | ||
It's required when the C name doesn't conform to Haskell naming requirements. | It's required when the C name doesn't conform to Haskell naming requirements. | ||
Although the Haskell FFI standard tells about many other calling conventions in addition to <code>ccall</code> (e.g. <code>cplusplus</code>, <code>jvm</code>, <code>net</code>) current Haskell implementations support only <code>ccall</code> and <code>stdcall</code>. The latter, also called the "Pascal" calling convention, is used to interface with WinAPI: | Although the Haskell FFI standard tells about many other calling conventions in | ||
addition to <code>ccall</code> (e.g. <code>cplusplus</code>, <code>jvm</code>, | |||
<code>net</code>) current Haskell implementations support only <code>ccall</code> | |||
and <code>stdcall</code>. The latter, also called the "Pascal" calling | |||
convention, is used to interface with WinAPI: | |||
<haskell> | <haskell> | ||
Line 1,105: | Line 1,231: | ||
</haskell> | </haskell> | ||
And finally, about the <code>safe</code>/<code>unsafe</code> specifier: a C routine imported with the <code>unsafe</code> keyword is called directly and the Haskell runtime is stopped while the C routine is executed (when there are several OS threads executing the Haskell program, only the current OS thread is delayed). This call doesn't allow recursively entering back into Haskell by calling any Haskell definition - the Haskell RTS is just not prepared for such an event. However, <code>unsafe</code> calls are as quick as calls in C. It's ideal for "momentary" calls that quickly return back to the caller. | And finally, about the <code>safe</code>/<code>unsafe</code> specifier: a C | ||
routine imported with the <code>unsafe</code> keyword is called directly and | |||
the Haskell runtime is stopped while the C routine is executed (when there are | |||
several OS threads executing the Haskell program, only the current OS thread is | |||
delayed). This call doesn't allow recursively entering back into Haskell by | |||
calling any Haskell definition - the Haskell RTS is just not prepared for such | |||
an event. However, <code>unsafe</code> calls are as quick as calls in C. It's | |||
ideal for "momentary" calls that quickly return back to the caller. | |||
When <code>safe</code> is specified, the C routine is called in a safe environment - the Haskell execution context is saved, so it's possible to call back to Haskell and, if the C call takes a long time, another OS thread may be started to execute Haskell code (of course, in threads other than the one that called the C code). This has its own price, though - around 1000 CPU ticks per call. | When <code>safe</code> is specified, the C routine is called in a safe | ||
environment - the Haskell execution context is saved, so it's possible to call | |||
back to Haskell and, if the C call takes a long time, another OS thread may be | |||
started to execute Haskell code (of course, in threads other than the one that | |||
called the C code). This has its own price, though - around 1000 CPU ticks per | |||
call. | |||
You can read more about interaction between FFI calls and Haskell concurrency in [[#readmore|[7]]]. | You can read more about interaction between FFI calls and Haskell concurrency | ||
in [[#readmore|[7]]]. | |||
=== Marshalling simple types === | === Marshalling simple types === | ||
Calling by itself is relatively easy; the real problem of interfacing languages with different data models is passing data between them. In this case, there is no guarantee that Haskell's <code>Int</code> is represented in memory the same way as C's <code>int</code>, nor Haskell's <code>Double</code> the same as C's <code>double</code> and so on. While on ''some'' platforms they are the same and you can write throw-away programs relying on these, the goal of portability requires you to declare foreign imports and exports using special types described in the FFI standard, which are guaranteed to correspond to C types. These are: | Calling by itself is relatively easy; the real problem of interfacing languages | ||
with different data models is passing data between them. In this case, there is | |||
no guarantee that Haskell's <code>Int</code> is represented in memory the same | |||
way as C's <code>int</code>, nor Haskell's <code>Double</code> the same as C's | |||
<code>double</code> and so on. While on ''some'' platforms they are the same | |||
and you can write throw-away programs relying on these, the goal of portability | |||
requires you to declare foreign imports and exports using special types | |||
described in the FFI standard, which are guaranteed to correspond to C types. | |||
These are: | |||
<haskell> | <haskell> | ||
Line 1,129: | Line 1,276: | ||
</haskell> | </haskell> | ||
Note that C routines <i>which behave like pure functions</i> (those whose results depend only on their arguments) are imported without <code>IO</code> in their return type. The <code>const</code> specifier in C is not reflected in Haskell types, so appropriate compiler checks are not performed. <!-- What would these be? --> | Note that C routines <i>which behave like pure functions</i> (those whose | ||
results depend only on their arguments) are imported without <code>IO</code> | |||
in their return type. The <code>const</code> specifier in C is not reflected | |||
in Haskell types, so appropriate compiler checks are not performed. <!-- What would these be? --> | |||
All these numeric types are instances of the same classes as their Haskell cousins (<code>Ord</code>, <code>Num</code>, <code>Show</code> and so on), so you may perform calculations on these data directly. Alternatively, you may convert them to native Haskell types. It's very typical to write simple wrappers around foreign imports and exports just to provide interfaces having native Haskell types: | All these numeric types are instances of the same classes as their Haskell | ||
cousins (<code>Ord</code>, <code>Num</code>, <code>Show</code> and so on), so | |||
you may perform calculations on these data directly. Alternatively, you may | |||
convert them to native Haskell types. It's very typical to write simple | |||
wrappers around foreign imports and exports just to provide interfaces having | |||
native Haskell types: | |||
<haskell> | <haskell> | ||
Line 1,162: | Line 1,317: | ||
=== Marshalling composite types === | === Marshalling composite types === | ||
A C array may be manipulated in Haskell as [http://haskell.org/haskellwiki/Arrays#StorableArray_.28module_Data.Array.Storable.29 StorableArray]. | A C array may be manipulated in Haskell as | ||
[http://haskell.org/haskellwiki/Arrays#StorableArray_.28module_Data.Array.Storable.29 StorableArray]. | |||
There is no built-in support for marshalling C structures and using C constants in Haskell. These are implemented in the c2hs preprocessor, though. | There is no built-in support for marshalling C structures and using C constants | ||
in Haskell. These are implemented in the c2hs preprocessor, though. | |||
Binary marshalling (serializing) of data structures of any complexity is implemented in the library module "Binary". | Binary marshalling (serializing) of data structures of any complexity is | ||
implemented in the library module "Binary". | |||
=== Dynamic calls === | === Dynamic calls === | ||
=== DLLs === | === DLLs === | ||
''because i don't have experience of using DLLs, can someone write into this section? Ultimately, we need to consider the following tasks:'' | ''because i don't have experience of using DLLs, can someone write into this | ||
section? Ultimately, we need to consider the following tasks:'' | |||
* using DLLs of 3rd-party libraries (such as ''ziplib'') | * using DLLs of 3rd-party libraries (such as ''ziplib'') | ||
* putting your own C code into a DLL to use in Haskell | * putting your own C code into a DLL to use in Haskell | ||
Line 1,179: | Line 1,338: | ||
== '''The dark side of the I/O monad''' == | == '''The dark side of the I/O monad''' == | ||
Unless you are a systems developer, postgraduate CS student, or have alternate (and eminent!) verifiable qualifications you should have '''no need whatsoever''' for this section - [https://stackoverflow.com/questions/9449239/unsafeperformio-in-threaded-applications-does-not-work here] is just one tiny example of what can go wrong if you don't know what you are doing. Look for other solutions! | Unless you are a systems developer, postgraduate CS student, or have alternate | ||
(and eminent!) verifiable qualifications you should have '''no need whatsoever''' | |||
for this section - | |||
[https://stackoverflow.com/questions/9449239/unsafeperformio-in-threaded-applications-does-not-work here] | |||
is just one tiny example of what can go wrong if you don't know what you are | |||
doing. Look for other solutions! | |||
=== '''unsafePerformIO''' === | === '''unsafePerformIO''' === | ||
Do you remember | |||
Do you remember this definition? | |||
<haskell> | |||
getChar >>= \c -> c | |||
</haskell> | |||
Let's try to "define" something with it: | |||
<haskell> | <haskell> | ||
getchar :: Char | getchar :: Char | ||
getchar = getChar >>= \c -> c | |||
get2chars = [getchar | get2chars :: String | ||
get2chars = [a, b] where a = getchar | |||
b = getchar | |||
</haskell> | </haskell> | ||
But what makes all of that so wrong? Besides <code>getchar</code> | |||
and <code>get2chars</code> not being I/O actions: | |||
# Because the Haskell compiler treats all functions as pure (not having side effects), it can avoid "unnecessary" calls to <code>getchar</code> and use one returned value twice; | # Because the Haskell compiler treats all functions as pure (not having side effects), it can avoid "unnecessary" calls to <code>getchar</code> and use one returned value twice; | ||
# Even if it does make two calls, there is no way to determine which call should be performed first. Do you want to return the two characters in the order in which they were read, or in the opposite order? Nothing in the definition of <code>get2chars</code> answers this question. | # Even if it does make two calls, there is no way to determine which call should be performed first. Do you want to return the two characters in the order in which they were read, or in the opposite order? Nothing in the definition of <code>get2chars</code> answers this question. | ||
Despite these problems, programmers coming from an imperative language background often look for a way to do this - disguise one or more I/O actions as a pure definition. Having seen procedural entities similar in appearance to: | Despite these problems, programmers coming from an imperative language | ||
background often look for a way to do this - disguise one or more I/O | |||
actions as a pure definition. Having seen procedural entities similar | |||
in appearance to: | |||
<haskell> | <haskell> | ||
Line 1,208: | Line 1,386: | ||
</haskell> | </haskell> | ||
would definitely be more appealing - for example, defining <code>readContents</code> as though it were a pure function: | would definitely be more appealing - for example, defining | ||
<code>readContents</code> as though it were a pure function: | |||
<haskell> | <haskell> | ||
Line 1,214: | Line 1,393: | ||
</haskell> | </haskell> | ||
will certainly simplify the code that uses it. However, those exact same problems are also lurking here: | will certainly simplify the code that uses it. However, those exact same | ||
problems are also lurking here: | |||
# Attempts to read the contents of files with the same name can be factored (''i.e.'' reduced to a single call) despite the fact that the file (or the current directory) can be changed between calls. Haskell considers all non-<code>IO</code> functions to be pure and feels free to merge multiple calls with the same parameters. | # Attempts to read the contents of files with the same name can be factored (''i.e.'' reduced to a single call) despite the fact that the file (or the current directory) can be changed between calls. Haskell considers all non-<code>IO</code> functions to be pure and feels free to merge multiple calls with the same parameters. | ||
# This call is not inserted in a sequence of | # This call is not inserted in a sequence of I/O actions all the way from <code>main</code> so the compiler doesn't know at what exact moment you want to execute this action. For example, if the file has one kind of contents at the beginning of the program and another at the end - which contents do you want to see? You have no idea when (or even if) this function is going to get invoked, because Haskell sees this function as pure and feels free to reorder the execution of any or all pure functions as needed. | ||
So, implementing supposedly-pure functions that interact with the '''Real World''' is considered to be '''Bad Behavior'''. Nice programmers never do it ;-) | So, implementing supposedly-pure functions that interact with the '''Real World''' | ||
is considered to be '''Bad Behavior'''. Nice programmers never do it <code>;-)</code> | |||
Nevertheless, there are (semi-official) ways to use I/O actions inside of pure functions | Nevertheless, there are (semi-official) ways to use I/O actions inside of pure | ||
functions - there is a ''(ahem)'' "special" definition that will (mis)use the | |||
Haskell implementation to run an I/O action. This particular (and dangerous) | |||
is: | |||
<haskell> | <haskell> | ||
Line 1,227: | Line 1,411: | ||
</haskell> | </haskell> | ||
Using <code>unsafePerformIO</code>, you could easily write "pure-looking | |||
functions" that actually do I/O inside. But don't do this without a real need, | |||
and remember to follow this rule: | |||
Using <code>unsafePerformIO</code>, you could easily write "pure-looking functions" that actually do I/O inside. But don't do this without a real need, and remember to follow this rule: | |||
* the compiler doesn't know that you are cheating; it still considers each non-<code>IO</code> function to be a pure one. Therefore, all the usual optimization rules can (and will!) be applied to its execution. | * the compiler doesn't know that you are cheating; it still considers each non-<code>IO</code> function to be a pure one. Therefore, all the usual optimization rules can (and will!) be applied to its execution. | ||
Line 1,246: | Line 1,422: | ||
* You don't rely on side-effects of this function, which may be not executed if its results are not needed. | * You don't rely on side-effects of this function, which may be not executed if its results are not needed. | ||
Let's investigate this problem more deeply. Function evaluation in Haskell is determined by a value's necessity - the language computes only the values that are really required to calculate the final result. But what does this mean with respect to the <code>main</code> action? To | Let's investigate this problem more deeply. Function evaluation in Haskell is | ||
determined by a value's necessity - the language computes only the values that | |||
are really required to calculate the final result. But what does this mean with | |||
respect to the <code>main</code> action? To run it to completion, all the | |||
intermediate I/O actions that are included in <code>main</code>'s chain need to | |||
be run. By using <code>unsafePerformIO</code> we call I/O actions outside of this | |||
chain. What guarantee do we have that they will be run at all? None. The only | |||
time they will be run is if running them is required to compute the overall | |||
function result (which in turn should be required to perform some action in the | |||
<code>main</code> chain). This is an example of Haskell's evaluation-by-need | |||
strategy. Now you should clearly see the difference: | |||
* An I/O action inside an I/O definition is guaranteed to execute as long as it is (directly or indirectly) inside the <code>main</code> chain - even when its result isn't used (because | * An I/O action inside an I/O definition is guaranteed to execute as long as it is (directly or indirectly) inside the <code>main</code> chain - even when its result isn't used (because it will be run anyway). You directly specify the order of the action's execution inside the I/O definition. | ||
* An I/O action | * An I/O action called by <code>unsafePerformIO</code> will be performed only if its result is really used. The evaluation order is not guaranteed and you should not rely on it (except when you're sure about whatever data dependencies may exist). | ||
I should also say that inside the <code>unsafePerformIO</code> call you can organize a small internal chain of I/O actions with the help of the same binding operators and/or <code>do</code> syntactic sugar we've seen above. So here's how we'd rewrite our previous (pure!) definition of <code>one</code> using <code>unsafePerformIO</code>: | I should also say that inside the <code>unsafePerformIO</code> call you can | ||
organize a small internal chain of I/O actions with the help of the same | |||
binding operators and/or <code>do</code> syntactic sugar we've seen above. So | |||
here's how we'd rewrite our previous (pure!) definition of <code>one</code> | |||
using <code>unsafePerformIO</code>: | |||
<haskell> | <haskell> | ||
Line 1,261: | Line 1,451: | ||
</haskell> | </haskell> | ||
and in this case ''all'' the | and in this case ''all'' the I/O actions in this chain will be run when | ||
the result of the <code>unsafePerformIO</code> call is needed. | |||
=== '''inlinePerformIO''' === | === '''inlinePerformIO''' === | ||
<code>inlinePerformIO</code> | The internal code for <code>inlinePerformIO</code> is similar to that of | ||
<code>unsafePerformIO</code>, sometimes having an <code>INLINE</code> pragma. | |||
Semantically <code>inlinePerformIO = unsafePerformIO</code> in as | |||
much as either of those have any semantics at all. | |||
Semantically <code>inlinePerformIO | |||
The difference of course is that <code>inlinePerformIO</code> is even less safe than <code>unsafePerformIO</code>. While ghc will try not to duplicate or common up different uses of <code>unsafePerformIO</code>, we aggressively inline <code>inlinePerformIO</code>. So you can really only use it where the I/O content is really properly pure, like reading from an immutable memory buffer (as in the case of <code>ByteString</code>s). However things like allocating new buffers should not be done inside <code>inlinePerformIO</code> since that can easily be floated out and performed just once for the whole program, so you end up with many things sharing the same buffer, which would be bad. | The difference of course is that <code>inlinePerformIO</code> is even less safe | ||
than <code>unsafePerformIO</code>. While ghc will try not to duplicate or | |||
common up different uses of <code>unsafePerformIO</code>, we aggressively | |||
inline <code>inlinePerformIO</code>. So you can really only use it where the | |||
I/O content is really properly pure, like reading from an immutable memory | |||
buffer (as in the case of <code>ByteString</code>s). However things like | |||
allocating new buffers should not be done inside <code>inlinePerformIO</code> | |||
since that can easily be floated out and performed just once for the whole | |||
program, so you end up with many things sharing the same buffer, which would | |||
be bad. | |||
So the rule of thumb is that I/O actions wrapped in <code>unsafePerformIO</code> have to be externally pure while with <code>inlinePerformIO</code> it has to be really, ''really'' pure or it'll all go horribly wrong. | So the rule of thumb is that I/O actions wrapped in <code>unsafePerformIO</code> | ||
have to be externally pure while with <code>inlinePerformIO</code> it has | |||
to be really, ''really'' pure or it'll all go horribly wrong. | |||
That said, here's some really hairy code. This should frighten any pure functional programmer... | That said, here's some really hairy code. This should frighten any pure | ||
functional programmer... | |||
<haskell> | <haskell> | ||
Line 1,311: | Line 1,500: | ||
</haskell> | </haskell> | ||
This does not adhere to my rule of thumb above. Don't ask exactly why we claim it's safe :-) (and if anyone really wants to know, ask Ross Paterson who did it first in the <code>Builder</code> monoid) | This does not adhere to my rule of thumb above. Don't ask exactly why we claim | ||
it's safe <code>:-)</code> (and if anyone really wants to know, ask Ross Paterson who did it | |||
first in the <code>Builder</code> monoid) | |||
=== '''unsafeInterleaveIO''' === | === '''unsafeInterleaveIO''' === | ||
Line 1,321: | Line 1,512: | ||
</haskell> | </haskell> | ||
and here's one clear reason why: | |||
<haskell> | <haskell> | ||
Line 1,331: | Line 1,520: | ||
</haskell> | </haskell> | ||
So don't let that type signature fool you - <code>unsafeInterleaveIO</code> | |||
also has to be used carefully! It too sets up its unsuspecting parameter to | |||
run lazily, instead of running in the <code>main</code> action chain, with the | |||
only difference being the result of running the parameter can only be used | |||
by another I/O action. But this is of little benefit - ideally the parameter | |||
and the <code>main</code> action chain should have no other interactions with | |||
each other, otherwise things can get ugly! | |||
At least you have some appreciation as to why <code>unsafeInterleaveIO</code> is, well '''unsafe!''' Just don't ask - to talk further is bound to cause grief and indignation. I won't say anything more about this ruffian I...use all the time (darn it!) | At least you have some appreciation as to why <code>unsafeInterleaveIO</code> | ||
is, well '''unsafe!''' Just don't ask - to talk further is bound to cause grief | |||
and indignation. I won't say anything more about this ruffian I...use all the | |||
time (darn it!) | |||
One can use <code>unsafePerformIO</code> (not <code>unsafeInterleaveIO</code>) to perform I/O operations not in some predefined order but by demand. For example, the following code: | One can use <code>unsafePerformIO</code> (not <code>unsafeInterleaveIO</code>) | ||
to perform I/O operations not in some predefined order but by demand. For | |||
example, the following code: | |||
<haskell> | <haskell> | ||
Line 1,342: | Line 1,542: | ||
</haskell> | </haskell> | ||
will perform the <code>getChar</code> I/O call only when the value of <code>c</code> is really required by the calling code, i.e. it this call will be performed lazily like any regular Haskell computation. | will perform the <code>getChar</code> I/O call only when the value of | ||
<code>c</code> is really required by the calling code, i.e. it this call will | |||
be performed lazily like any regular Haskell computation. | |||
Now imagine the following code: | Now imagine the following code: | ||
Line 1,351: | Line 1,553: | ||
</haskell> | </haskell> | ||
The three characters inside this list will be computed on demand too, and this means that their values will depend on the order they are consumed. It is not what we usually want. | The three characters inside this list will be computed on demand too, and this | ||
means that their values will depend on the order they are consumed. It is not | |||
what we usually want. | |||
<code>unsafeInterleaveIO</code> solves this problem - it performs I/O only on demand but allows you to define the exact ''internal'' execution order for parts of your data structure. | <code>unsafeInterleaveIO</code> solves this problem - it performs I/O only on | ||
demand but allows you to define the exact ''internal'' execution order for | |||
parts of your data structure. | |||
* <code>unsafeInterleaveIO</code> accepts an I/O action as a parameter and returns another I/O action as the result: | * <code>unsafeInterleaveIO</code> accepts an I/O action as a parameter and returns another I/O action as the result: | ||
Line 1,373: | Line 1,579: | ||
</haskell> | </haskell> | ||
This code will be executed only at the moment when the value of <code>str</code> is really demanded. In this moment, <code>getChar</code> will be performed (with its result assigned to <code>c</code>) and a new lazy-I/O closure will be created - for <code>s</code>. This new closure also contains a link to a <code>myGetContents</code> call. | This code will be executed only at the moment when the value of <code>str</code> | ||
is really demanded. In this moment, <code>getChar</code> will be performed | |||
(with its result assigned to <code>c</code>) and a new lazy-I/O closure will be | |||
created - for <code>s</code>. This new closure also contains a link to a | |||
<code>myGetContents</code> call. | |||
The resulting list is then returned. It contains the <code>Char</code> that was | |||
just read and a link to another <code>myGetContents</code> call as a way to | |||
compute the rest of the list. Only at the moment when the next value in the | |||
list is required will this operation be performed again. | |||
As a final result, we can postpone the read of the second <code>Char</code> in the list before the first one, but have lazy reading of characters as a whole - bingo! | As a final result, we can postpone the read of the second <code>Char</code> in | ||
the list before the first one, but have lazy reading of characters as a whole - | |||
bingo! | |||
PS: of course, actual code should include EOF checking; also note that you can read multiple characters/records at each call: | PS: of course, actual code should include EOF checking; also note that you can | ||
read multiple characters/records at each call: | |||
<haskell> | <haskell> | ||
myGetContents = do | myGetContents = do | ||
l <- replicateM 512 getChar | |||
s <- unsafeInterleaveIO myGetContents | s <- unsafeInterleaveIO myGetContents | ||
return ( | return (l++s) | ||
</haskell> | </haskell> | ||
and we can rewrite <code>myGetContents</code> to avoid needing to use <code>unsafeInterleaveIO</code> where it's called: | and we can rewrite <code>myGetContents</code> to avoid needing to use | ||
<code>unsafeInterleaveIO</code> where it's called: | |||
<haskell> | <haskell> | ||
myGetContents = unsafeInterleaveIO $ do | myGetContents = unsafeInterleaveIO $ do | ||
l <- replicateM 512 getChar | |||
s <- myGetContents | s <- myGetContents | ||
return ( | return (l++s) | ||
</haskell> | </haskell> | ||
== Welcome to the machine: the | == Welcome to the machine: taking off the covers == | ||
A little disclaimer: I should say that I'm not describing here exactly what a monad is (I don't even completely understand it myself) and my explanation shows only one ''possible'' way to implement the I/O monad in Haskell. For example, the hbc compiler and the Hugs interpreter implements the I/O monad via continuations [[#readmore|[9]]]. I also haven't said anything about exception handling, which is a natural part of the "monad" concept. You can read the [[All About Monads]] guide to learn more about these topics. | A little disclaimer: I should say that I'm not describing here exactly what a | ||
monad is (I don't even completely understand it myself) and my explanation | |||
shows only one ''possible'' way to implement the I/O monad in Haskell. For | |||
example, the hbc compiler and the Hugs interpreter implements the I/O monad via | |||
continuations [[#readmore|[9]]]. I also haven't said anything about exception | |||
handling, which is a natural part of the "monad" concept. You can read the | |||
[[All About Monads]] guide to learn more about these topics. | |||
But there is some good news: | But there is some good news: the I/O monad understanding you've just acquired | ||
will work with any implementation and with many other monads. | |||
=== The [[GHC]] implementation === | |||
:<haskell> | :<haskell> | ||
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #)) | newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #)) | ||
</haskell> | </haskell> | ||
It uses the <code>State# RealWorld</code> type | It uses the <code>State# RealWorld</code> type and the strict tuple type | ||
<code>(# ... #)</code> for optimization. It also uses an <code>IO</code> data | |||
constructor. Nevertheless, there are no significant changes from the standpoint | |||
of our explanation. | |||
Of course, other compilers e.g. yhc/nhc (jhc, too?) define <code>IO</code> in other ways. | Of course, other compilers e.g. yhc/nhc (jhc, too?) define <code>IO</code> in | ||
other ways. | |||
=== The [[Yhc]]/nhc98 implementation === | === The [[Yhc]]/nhc98 implementation === | ||
Line 1,423: | Line 1,650: | ||
</haskell> | </haskell> | ||
This implementation makes the <code>World</code> disappear somewhat[[#readmore|[10]]], and returns <code>Either</code> a result of type <code>a</code>, or if an error occurs then <code>IOError</code>. The lack of the <code>World</code> on the right-hand side of the function can only be done because the compiler knows special things about the <code>IO</code> type, and won't overoptimise it. | This implementation makes the <code>World</code> disappear somewhat[[#readmore|[10]]], | ||
and returns <code>Either</code> a result of type <code>a</code>, or if an error | |||
occurs then <code>IOError</code>. The lack of the <code>World</code> on the | |||
right-hand side of the function can only be done because the compiler knows | |||
special things about the <code>IO</code> type, and won't overoptimise it. | |||
== <span id="readmore"></span>Further reading == | == <span id="readmore"></span>Further reading == | ||
[1] This | [1] This manual is largely based on Simon Peyton Jones's paper [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.9123&rep=rep1&type=pdf Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell]. I hope that my manual improves his original explanation of the Haskell I/O system and brings it closer to the point of view of new Haskell programmers. But if you need to learn about concurrency, exceptions and the FFI in Haskell/GHC, the original paper is the best source of information. | ||
[2] You can find more information about concurrency, the FFI and STM at the [[GHC/Concurrency#Starting points]] page. | [2] You can find more information about concurrency, the FFI and STM at the [[GHC/Concurrency#Starting points]] page. | ||
Line 1,446: | Line 1,677: | ||
[9] [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.3579&rep=rep1&type=pdf How to Declare an Imperative] by Phil Wadler provides an explanation of how this can be done. | [9] [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.91.3579&rep=rep1&type=pdf How to Declare an Imperative] by Phil Wadler provides an explanation of how this can be done. | ||
Do you have more questions? Ask in the | |||
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list]. | |||
Do you have more questions? Ask in the [http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list]. | |||
== To-do list == | == To-do list == | ||
If you are interested in adding more information to this manual, please add your questions/topics here. | If you are interested in adding more information to this manual, please add | ||
your questions/topics here. | |||
Topics: | Topics: | ||
Line 1,459: | Line 1,690: | ||
Questions: | Questions: | ||
* split <code>(>>=)</code>/<code>(>>)</code>/return section and <code>do</code> section, more examples of using binding operators | * split <code>(>>=)</code>/<code>(>>)</code>/<code>return</code> section and <code>do</code> section, more examples of using binding operators | ||
* <code>IORef</code> detailed explanation (==<code>const*</code>), usage examples, syntax sugar, unboxed refs | * <code>IORef</code> detailed explanation (==<code>const*</code>), usage examples, syntax sugar, unboxed refs | ||
* explanation of how the actual data "in" mutable references are inside <code>RealWorld</code>, rather than inside the references themselves (<code>IORef</code>, <code>IOArray</code> & co.) | * explanation of how the actual data "in" mutable references are inside GHC's <code>RealWorld</code>, rather than inside the references themselves (<code>IORef</code>, <code>IOArray</code> & co.) | ||
* control structures developing - much more examples | * control structures developing - much more examples | ||
* <code>unsafePerformIO</code> usage examples: global variable, <code>ByteString</code>, other examples | * <code>unsafePerformIO</code> usage examples: global variable, <code>ByteString</code>, other examples | ||
* how <code>unsafeInterLeaveIO</code> can be seen as a kind of concurrency, and therefore isn't so unsafe (unlike <code>unsafeInterleaveST</code> which really is unsafe) | * how <code>unsafeInterLeaveIO</code> can be seen as a kind of concurrency, and therefore isn't so unsafe (unlike <code>unsafeInterleaveST</code> which really is unsafe) | ||
* discussion about different senses of <code>safe</code>/<code>unsafe</code> (like breaking equational reasoning vs. invoking undefined behaviour (so can corrupt the run-time system)) | * discussion about different senses of <code>safe</code>/<code>unsafe</code> (like breaking equational reasoning vs. invoking undefined behaviour (so can corrupt the run-time system)) | ||
* actual GHC | * actual code used by GHC - how to write low-level definitions based on example of how <code>newIORef</code> is implemented | ||
This manual is collective work, so feel free to add more information to it yourself. The final goal is to collectively develop a comprehensive manual for using the I/O monad. | This manual is collective work, so feel free to add more information to it | ||
yourself. The final goal is to collectively develop a comprehensive manual | |||
for using the I/O monad. | |||
---- | ---- | ||
[[Category:Tutorials]] | [[Category:Tutorials]] |
Latest revision as of 00:00, 8 March 2025
Haskell I/O can be a source of confusion and surprises for new Haskellers - if that's you, a good place to start is the Introduction to IO which can help you learn the basics (e.g. the syntax of I/O expressions) before continuing on.
While simple I/O code in Haskell looks very similar to its equivalents in imperative languages, attempts to write somewhat more complex code often result in a total mess. This is because Haskell I/O is really very different in how it actually works.
The following text is an attempt to explain the inner workings of I/O in Haskell. This explanation should help you eventually learn all the smart I/O tips. Moreover, I've added a detailed explanation of various traps you might encounter along the way. After reading this text, you will be well on your way towards mastering I/O in Haskell.
Haskell is a pure language
Haskell is a pure language and even the I/O system can't break this purity.
Being pure means that the result of any function call is fully determined by
its arguments. Imperative routines like rand()
or
getchar()
in C, which return different results on each call, are
simply impossible to write in Haskell. Moreover, Haskell functions can't have
side effects, which means that they can't make any changes "outside the Haskell
program", like changing files, writing to the screen, printing, sending data
over the network, and so on. These two restrictions together mean that any
function call can be replaced by the result of a previous call with the same
parameters, and the language guarantees that all these rearrangements will
not change the program result! For example, the hyperbolic cosine function
cosh
can be defined in Haskell as:
cosh r = (exp r + 1/exp r)/2
using identical calls to exp
, which is another function. So
cosh
can instead call exp
once, and reuse the result:
cosh r = (x + 1/x)/2 where x = exp r
Let's compare this to C: optimizing C compilers try to guess which routines have no side effects and don't depend on mutable global variables. If this guess is wrong, an optimization can change the program's semantics! To avoid this kind of disaster, C optimizers are conservative in their guesses or require hints from the programmer about the purity of routines.
Compared to an optimizing C compiler, a Haskell compiler is a set of pure mathematical transformations. This results in much better high-level optimization facilities. Moreover, pure mathematical computations can be much more easily divided into several threads that may be executed in parallel, which is increasingly important in these days of multi-core CPUs. Finally, pure computations are less error-prone and easier to verify, which adds to Haskell's robustness and to the speed of program development using Haskell.
Haskell's purity allows the compiler to call only functions whose results are
really required to calculate the final value of a top-level definition (e.g.
main
) - this is called lazy evaluation. It's a great thing for
pure mathematical computations, but how about I/O actions? Something like
putStrLn "Press any key to begin formatting"
can't return any meaningful result value, so how can we ensure that the compiler will not omit or reorder its execution? And in general: How we can work with stateful algorithms and side effects in an entirely lazy language? This question has had many different solutions proposed while Haskell was developed (see A History of Haskell), with one solution eventually making its way into the current standard.
I/O in Haskell, simplified
So what is actually inside an I/O action? Let's look at how MicroHs defines the I/O type:
data IO a
just as described on page 95 of 329 in the Haskell 2010 Report: no visible data constructors. So someone who is implementing Haskell could in fact define functions and I/O actions in much the same way. The only difference that really matters is this:
- Only I/O actions are allowed to make changes "outside the Haskell program".
(Or to state it more formally: only I/O actions are allowed to have externally visible side effects).
It doesn't get much simpler than that :-D
The question of purity
So if Haskell uses the same side effects for I/O as an imperative language, how can it possibly be "pure"?
Because of what doesn't work in Haskell:
\msg x -> seq (putStrLn msg) x
No, that won't work. And neither will this:
getChar >>= \c -> c
Remember, Haskell functions can't have side effects - they can't make any changes "outside the Haskell program". Therefore if either of these examples really did work, then they would no longer be Haskell functions! (More importantly, just imagine if those two were being used in parallel somewhere in a program...)
So in Haskell, the result of running an I/O action must be another I/O action. This restriction ensures that Haskell functions really are pure.
Running with I/O
So, main
just has the type IO ()
. Let's look at
main
calling getChar
two times:
main :: IO ()
main = getChar >>= \a ->
getChar >>= \b ->
return ()
By defining a Monad
instance for IO a
:
unitIO :: a -> IO a -- implemented
bindIO :: IO a -> (a -> IO b) -> IO b -- elsewhere
instance Monad IO where
return = unitIO
(>>=) = bindIO
we can then expand main
to get:
main = getChar `bindIO` (\a ->
getChar `bindIO` (\b ->
unitIO ()))
Now to run main
:
main = getChar `bindIO` (\a -> ...)
doesn't require evaluation, continuing;- run
getChar
to obtain a characterc1 :: Char
; - apply
(\a -> ...)
toc1
; - then evaluate the result to obtain the next action
getChar `bindIO` (\b -> ...)
; - run
getChar
to obtain another characterc2 :: Char
; - apply
(\b -> ...)
toc2
; - then evaluate the result to obtain the next action
unitIO ()
; - run
unitIO ()
to obtain() :: ()
, which ends the program.
From that example we can see that:
- Each action is run - it doesn't matter if what's obtained from running it isn't actually used.
- Each action is run in the order it appears in the program - there is no reordering of actions.
- Each action is run once, then the next action is obtained or the program ends - if a program only uses an action once, then it is only run once.
Overall, in order to obtain the final value of main
, each I/O
action that is called from main
- directly or indirectly - is
run. This means that each action inserted in the chain will be performed
just at the moment (relative to the other I/O actions) when we intended it
to be called. Let's consider the following program:
main = do a <- ask "What is your name?"
b <- ask "How old are you?"
return ()
ask s = do putStr s
readLn
Now you have enough knowledge to rewrite it in a low-level way and check that each operation that should be performed will really be performed with the arguments it should have and in the order we expect.
But what about conditional execution? No problem. Let's define the well-known
when
function:
when :: Bool -> IO () -> IO ()
when condition action =
if condition
then action
else return ()
Because it's a function:
- it will be applied to two arguments;
- its result (the conditional expression) will be evaluated;
- then the chosen action will be run.
As you can see, we can easily include or exclude from the execution chain I/O
actions depending on the data values. If condition
will be
False
on the call of when
, action
will
never be run.
Loops and more complex control structures can be implemented in the same way. Try it as an exercise!
(>>=)
and do
notation
All beginners (including me) start by thinking that do
is some
super-awesome statement that executes I/O actions. That's wrong - do
is just syntactic sugar that simplifies the writing of definitions that use I/O
(and also other monads, but that's beyond the scope of this manual). do
notation eventually gets translated to a series of I/O actions much like we've
manually written above. This simplifies the gluing of several
I/O actions together. You don't need to use do
for just one
action; for example,
main = do putStr "Hello!"
is desugared to:
main = putStr "Hello!"
Let's examine how to desugar a do
-expression with multiple actions
in the following example:
main = do putStr "What is your name?"
putStr "How old are you?"
putStr "Nice day!"
The do
-expression here just joins several I/O actions that should
be performed sequentially. It's translated to sequential applications of one
of the so-called "binding operators", namely (>>)
:
main = (putStr "What is your name?")
>> ( (putStr "How old are you?")
>> (putStr "Nice day!")
)
Defining (>>)
looks easy:
(>>) :: IO a -> IO b -> IO b
action1 >> action2 = action1 >>= \_ -> action2
Now you can substitute the definition of (>>)
at the places of
its usage and check that program constructed by the do
desugaring
is actually the same as we could write by using I/O actions manually.
A more complex example involves the binding of variables using <-
:
main = do a <- readLn
print a
This code is desugared into:
main = readLn
>>= (\a -> print a)
where (>>=)
corresponds to bindIO
.
As you now know, the (>>)
binding operator silently ignores
the value of its first action and returns as an overall result the result of
its second action only. On the other hand, the (>>=)
binding
operator (note the extra =
at the end) allows us to use the result
of its first action - it gets passed as an additional parameter to the second
one!
You can use (>>)
and (>>=)
to simplify your program.
For example, in the code above we don't need to introduce the variable, because
the result of running readLn
can be passed directly to
print
:
main = readLn >>= print
As you see, the notation:
do x <- action1
action2
where action1
has type IO a
and action2
has type IO b
, translates
into:
action1 >>= (\x -> action2)
where the second argument of (>>=)
has the type
a -> IO b
. It's the way
the <-
binding is processed - the name on the left-hand side of
<-
just becomes a parameter of subsequent operations represented
as one large I/O action. Note also that if action1
has type
IO a
then x
will just have type a
; you can think of the effect of <-
as "unpacking" the I/O value of action1
into x
.
Note also that <-
is not a true operator; it's pure syntax, just
like do
itself. Its meaning results only from the way it gets
desugared.
Look at the next example:
main = do putStr "What is your name?"
a <- readLn
putStr "How old are you?"
b <- readLn
print (a,b)
This code is desugared into:
main = putStr "What is your name?"
>> readLn
>>= \a -> putStr "How old are you?"
>> readLn
>>= \b -> print (a,b)
I omitted the parentheses here; both the (>>)
and the
(>>=)
operators are left-associative, but lambda-bindings
always stretches as far to the right as possible, which means that the
a
and b
bindings introduced here are valid for all
remaining actions. As an exercise, add the parentheses yourself and translate
this definition into action-level code. I
think it should be enough to help you finally realize how the do
translation and binding operators work.
Oh, no! I forgot the third monadic operator: return
. But that's
understandable - it does very little! The resulting I/O action immediately
returns its given argument (when it is run).
How about translating a simple example of return
usage? Say,
main = do a <- readLn
return (a*2)
Programmers with an imperative language background often think that
return
in Haskell, as in other languages, immediately returns
from the I/O definition. As you can see in its definition (and even just from
its type!), such an assumption is totally wrong. The only purpose of using
return
is to "lift" some value (of type a
) into the
result of a whole action (of type IO a
) and therefore it should
generally be used only as the last executed action of some I/O sequence. For
example try to translate the following definition into the corresponding
low-level code:
main = do a <- readLn
when (a>=0) $ do
return ()
print "a is negative"
and you will realize that the print
call is executed even for
non-negative values of a
. If you need to escape from the middle
of an I/O definition, you can use an if
expression:
main = do a <- readLn
if (a>=0)
then return ()
else print "a is negative"
Moreover, Haskell layout rules allow us to use the following layout:
main = do a <- readLn
if (a>=0) then return ()
else do
print "a is negative"
...
that may be useful for escaping from the middle of a longish
do
-expression.
Last exercise: implement a function liftM
that lifts operations
on plain values to the operations on monadic ones. Its type signature:
liftM :: (a -> b) -> (IO a -> IO b)
If that's too hard for you, start with the following high-level definition and rewrite it in low-level fashion:
liftM f action = do x <- action
return (f x)
Mutable data (references, arrays, hash tables...)
As you should know, every name in Haskell is bound to one fixed (immutable) value. This greatly simplifies understanding algorithms and code optimization, but it's inappropriate in some cases. As we all know, there are plenty of algorithms that are simpler to implement in terms of updatable variables, arrays and so on. This means that the value associated with a variable, for example, can be different at different execution points, so reading its value can't be considered as a pure function. Imagine, for example, the following code:
main = do let a0 = readVariable varA
_ = writeVariable varA 1
a1 = readVariable varA
print (a0, a1)
Does this look strange?
- The two calls to
readVariable
look the same, so the compiler can just reuse the value returned by the first call. - The result of the
writeVariable
call isn't used so the compiler can (and will!) omit this call completely. - These three calls may be rearranged in any order because they appear to be independent of each other.
This is obviously not what was intended. What's the solution? You already know this - use I/O actions! Doing that guarantees:
- the result of the "same" action (such as
readVariable varA
) will not be reused - each action will have to be executed
- the execution order will be retained as written
So, the code above really should be written as:
import Data.IORef
main = do varA <- newIORef 0 -- Create and initialize a new variable
a0 <- readIORef varA
writeIORef varA 1
a1 <- readIORef varA
print (a0, a1)
Here, varA
has the type IORef Int
which means "a variable (reference) in the I/O monad holding a value of type
Int
". newIORef
creates a new variable (reference)
and returns it, and then read/write actions use this reference. The value
returned by the readIORef varA
action depends not only on the variable involved but also on the moment this
operation is performed so it can return different values on each call.
Arrays, hash tables and any other mutable data structures are defined in the same way - for each of them, there's an operation that creates new "mutable values" and returns a reference to it. Then value-specific read and write operations in the I/O monad are used. The following code shows an example using mutable arrays:
import Data.Array.IO
main = do arr <- newArray (1,10) 37 :: IO (IOArray Int Int)
a <- readArray arr 1
writeArray arr 1 64
b <- readArray arr 1
print (a, b)
Here, an array of 10 elements with 37 as the initial value at each location is
created. After reading the value of the first element (index 1) into
a
this element's value is changed to 64 and then read again into
b
. As you can see by executing this code, a
will be
set to 37 and b
to 64.
Other state-dependent operations are also often implemented with I/O actions.
For example, a random number generator should return a different value on each
call. It looks natural to give it a type involving IO
:
rand :: IO Int
Moreover, when you import a C routine you should be careful - if this routine
is impure, i.e. its result depends on something "outside the Haskell program"
(file system, memory contents, its own static
internal state and
so on), you should give it an IO
type. Otherwise, the compiler
can "optimize" repetitive calls to the definition with the same parameters!
For example, we can write a non-IO
type for:
foreign import ccall
sin :: Double -> Double
because the result of sin
depends only on its argument, but
foreign import ccall
tell :: Int -> IO Int
If you will declare tell
as a pure function (without
IO
) then you may get the same position on each call!
Encapsulated mutable data: ST
If you're going to be doing things like sending text to a screen or reading
data from a scanner, IO
is the type to start with - you can then
customise existing I/O operations or add new ones as you see fit. But what if
that shiny-new (or classic) algorithm you're working on really only needs
mutable state - then having to drag that IO
type from
main
all the way through to wherever you're implementing the
algorithm can get quite irritating.
Fortunately there is a better way! One that remains totally pure and yet allows the use of references, arrays, and so on - and it's done using, you guessed it, Haskell's versatile type system (and one extension).
Remember our definition of IO
?
data IO a
Well, the new ST
type makes just one change - in theory, it can
be used with any suitable state type:
data ST s a
If we wanted to, we could even use ST
to define IO
:
type IO a = ST RealWorld a -- RealWorld defined elsewhere
Let's add some extra definitions:
newSTRef :: a -> ST s (STRef s a) -- these are
readSTRef :: STRef s a -> ST s a -- usually
writeSTRef :: STRef s a -> a -> ST s () -- primitive
newSTArray :: Ix i => (i, i) -> ST s (STArray s i e) -- also usually primitive
⋮
unitST :: a -> ST s a
bindST :: ST s a -> (a -> ST s b) -> ST s b
instance Monad (ST s) where
return = unitST
(>>=) = bindST
...that's right - this new ST
type is also monadic!
So what's the big difference between the ST
and IO
types? In one word - runST
:
runST :: (forall s . ST s a) -> a
Yes - it has a very unusual type. But that type allows you to run your stateful computation as if it was a pure definition!
The s
type variable in ST
is the type of the local
state. Moreover, all the fun mutable stuff available for ST
is
quantified over s
:
newSTRef :: a -> ST s (STRef s a)
newArray_ :: Ix i => (i, i) -> ST s (STArray s i e)
So why does runST
have such a funky type? Let's see what would
happen if we wrote
makeSTRef :: a -> STRef s a
makeSTRef a = runST (newSTRef a)
This fails, because newSTRef a
doesn't work for all state types
s
- it only works for the s
from the return type
STRef s a
.
This is all sort of wacky, but the result is that you can only run an
ST
computation where the output type is functionally pure, and
makes no references to the internal mutable state of the computation. In
exchange for that, there's no access to I/O operations like writing to or
reading from the console. The monadic ST
type only has references,
arrays, and such that are useful for performing pure computations.
Due to how similar IO
and ST
are internally, there's
this function:
stToIO :: ST RealWorld a -> IO a
The difference is that ST
uses the type system to forbid unsafe
behavior like extracting mutable objects from their safe ST
wrapping, but allowing purely functional outputs to be performed with all the
handy access to mutable references and arrays.
For example, here's a particularly convoluted way to compute the integer that comes after zero:
oneST :: ST s Integer -- note that this works correctly for any s
oneST = do var <- newSTRef 0
modifySTRef var (+1)
readSTRef var
one :: Int
one = runST oneST
I/O actions as values
By this point you should understand why it's impossible to use I/O actions inside non-I/O (pure) functions: when needed, fully-applied functions are always evaluated - they aren't run like I/O actions. In addition, the prohibition of using I/O actions inside pure functions is maintained by the type system (as it usually is in Haskell).
But while pure code can't be used to run I/O actions, it can work with them as with any other value - I/O actions can be stored in data structures, passed as parameters, returned as results, collected in lists or in tuples. But what won't work is something like:
\ msg x -> case putStrLn msg of _ -> x
because it will be treated as a function, not an I/O action.
To run an I/O action, we need to make it part of main
:
- either directly:
main = action
- or in the "action chain" of another action which is already a part of the
main
"chain":
main = ... >>= \ _ -> action >>= ...
Only then will the action be run. For example, in:
main = do let skip2chars = getChar >> getChar >> return ()
putStr "Press two keys"
skip2chars
return ()
the non-let
actions are run in the exact order in which they're
written.
Example: a list of I/O actions
Let's try defining a list of I/O actions:
ioActions :: [IO ()]
ioActions = [(print "Hello!"),
(putStr "just kidding"),
(getChar >> return ())
]
I used additional parentheses around each action, although they aren't really required. If you still can't believe that these actions won't be run immediately, remember that in this expression:
\ b -> if b then (putStr "started...") (putStrLn "completed.")
both I/O actions won't immediately be run either.
Well, now we want to execute some of these actions. No problem, just insert
them into the main
chain:
main = do head ioActions
ioActions !! 1
last ioActions
Looks strange, right? Really, any I/O action that you write in a
do
-expression (or use as a parameter for the
(>>)
/(>>=)
operators) is an expression returning a
result of type IO a
for
some type a
. Typically, you use some function that has the type
x -> y -> ... -> IO a
and provide all the x
, y
, etc. parameters. But you're
not limited to this standard scenario - don't forget that Haskell is a
functional language and you're free to evaluate any value as required
(recall that IO a
is
really a function type) in any possible way. Here we just extracted several
functions from the list - no problem. This value can also be constructed
on-the-fly, as we've done in the previous example - that's also OK.
Want to see this value passed as a parameter? Just look at the
definition of when
. Hey, we can buy, sell, and rent these I/O
actions just like we can with any other values! For example, let's
define a function that executes all the I/O actions in the list:
sequence_ :: [IO a] -> IO ()
sequence_ [] = return ()
sequence_ (x:xs) = do x
sequence_ xs
No smoke or mirrors - we just extract I/O actions from the list and insert
them into a chain of I/O operations that should be performed one after another
(in the same order that they occurred in the list) to obtain the end result
of the entire sequence_
call.
With the help of sequence_
, we can rewrite our last main
action as:
main = sequence_ ioActions
Haskell's ability to work with I/O actions just like other values
allows us to define control structures of arbitrary
complexity. Try, for example, to define a control structure that repeats an
action until it returns the False
result:
while :: IO Bool -> IO ()
while action = ???
Most programming languages don't allow you to define control structures at all, and those that do often require you to use a macro-expansion system. In Haskell, control structures are just trivial functions anyone can write.
Example: returning an I/O action as a result
How about returning an I/O action as the result of a function? Well, we've done this for each I/O definition - they all return I/O actions built up from other I/O actions (or themselves, if they're recursive). While we usually just execute them as part of a higher-level I/O definition, it's also possible to just collect them without actual execution:
main = do let a = sequence ioActions
b = when True getChar
c = getChar >> getChar >> return ()
putStr "These let-bindings are not executed!"
These assigned I/O actions can be used as parameters to other definitions, or
written to global variables, or processed in some other way, or just executed
later, as we did in the example with skip2chars
.
But how about returning a parameterized I/O action from an I/O definition? Here's a definition that returns the i'th byte from a file represented as a Handle:
readi h i = do hSeek h AbsoluteSeek i
hGetChar h
So far so good. But how about a definition that returns the i'th byte of a file with a given name without reopening it each time?
readfilei :: String -> IO (Integer -> IO Char)
readfilei name = do h <- openFile name ReadMode
return (readi h)
As you can see, it's an I/O definition that opens a file and returns...an I/O
action that will read the specified byte. But we can go further and include
the readi
body in readfilei
:
readfilei name = do h <- openFile name ReadMode
let readi h i = do hSeek h AbsoluteSeek i
hGetChar h
return (readi h)
That's a little better. But why do we add h
as a parameter to
readi
if it can be obtained from the environment where readi
is now defined? An even shorter version is this:
readfilei name = do h <- openFile name ReadMode
let readi i = do hSeek h AbsoluteSeek i
hGetChar h
return readi
What have we done here? We've build a parameterized I/O action involving local
names inside readfilei
and returned it as the result. Now it can
be used in the following way:
main = do myfile <- readfilei "test"
a <- myfile 0
b <- myfile 1
print (a,b)
This way of using I/O actions is very typical for Haskell programs - you just construct one or more I/O actions that you need, with or without parameters, possibly involving the parameters that your "constructor" received, and return them to the caller. Then these I/O actions can be used in the rest of the program without any knowledge of how you actually implemented them. One thing this can be used for is to partially emulate the OOP (or more precisely, the ADT) programming paradigm.
Example: a memory allocator generator
As an example, one of my programs has a module which is a memory suballocator. It receives the address and size of a large memory block and returns two specialised I/O operations - one to allocate a subblock of a given size and the other to free the allocated subblock:
memoryAllocator :: Ptr a -> Int -> IO (Int -> IO (Ptr b),
Ptr c -> IO ())
memoryAllocator buf size = do ......
let alloc size = do ...
...
free ptr = do ...
...
return (alloc, free)
How this is implemented? alloc
and free
work with
references created inside the memoryAllocator
definition. Because
the creation of these references is a part of the memoryAllocator
I/O-action chain, a new independent set of references will be created for each
memory block for which memoryAllocator
is called:
memoryAllocator buf size =
do start <- newIORef buf
end <- newIORef (buf `plusPtr` size)
...
These two references are read and written in the alloc
and
free
definitions (we'll implement a very simple memory allocator
for this example):
...
let alloc size = do addr <- readIORef start
writeIORef start (addr `plusPtr` size)
return addr
let free ptr = do writeIORef start ptr
What we've defined here is just a pair of closures that use state available at the moment of their definition. As you can see, it's as easy as in any other functional language, despite Haskell's lack of direct support for impure routines.
The following example uses the operations returned by memoryAllocator
,
to simultaneously allocate/free blocks in two independent memory buffers:
main = do buf1 <- mallocBytes (2^16)
buf2 <- mallocBytes (2^20)
(alloc1, free1) <- memoryAllocator buf1 (2^16)
(alloc2, free2) <- memoryAllocator buf2 (2^20)
ptr11 <- alloc1 100
ptr21 <- alloc2 1000
free1 ptr11
free2 ptr21
ptr12 <- alloc1 100
ptr22 <- alloc2 1000
Example: emulating OOP with record types
Let's implement the classical OOP example: drawing figures. There are figures of different types: circles, rectangles and so on. The task is to create a heterogeneous list of figures. All figures in this list should support the same set of operations: draw, move and so on. We will define these operations using I/O actions. Instead of a "class" let's define a structure from which all of the required operations can be accessed:
data Figure = Figure { draw :: IO (),
move :: Displacement -> IO ()
}
type Displacement = (Int, Int) -- horizontal and vertical displacement in points
The constructor of each figure's type should just return a Figure
record:
circle :: Point -> Radius -> IO Figure
rectangle :: Point -> Point -> IO Figure
type Point = (Int, Int) -- point coordinates
type Radius = Int -- circle radius in points
We will "draw" figures by just printing their current parameters. Let's start
with implementing simplified circle
and rectangle
constructors, without actual move
support:
circle center radius = do
let description = " Circle at "++show center++" with radius "++show radius
return $ Figure { draw = putStrLn description }
rectangle from to = do
let description = " Rectangle "++show from++"-"++show to)
return $ Figure { draw = putStrLn description }
As you see, each constructor just returns a fixed draw
operation
that prints parameters with which the concrete figure was created. Let's test
it:
drawAll :: [Figure] -> IO ()
drawAll figures = do putStrLn "Drawing figures:"
mapM_ draw figures
main = do figures <- sequence [circle (10,10) 5,
circle (20,20) 3,
rectangle (10,10) (20,20),
rectangle (15,15) (40,40)]
drawAll figures
Now let's define "full-featured" figures that can actually be moved around. In
order to achieve this, we should provide each figure with a mutable variable
that holds each figure's current screen location. The type of this variable
will be IORef Point
. This
variable should be created in the figure constructor and manipulated in I/O
operations (closures) enclosed in the Figure
record:
circle center radius = do
centerVar <- newIORef center
let drawF = do center <- readIORef centerVar
putStrLn (" Circle at "++show center
++" with radius "++show radius)
let moveF (addX,addY) = do (x,y) <- readIORef centerVar
writeIORef centerVar (x+addX, y+addY)
return $ Figure { draw=drawF, move=moveF }
rectangle from to = do
fromVar <- newIORef from
toVar <- newIORef to
let drawF = do from <- readIORef fromVar
to <- readIORef toVar
putStrLn (" Rectangle "++show from++"-"++show to)
let moveF (addX,addY) = do (fromX,fromY) <- readIORef fromVar
(toX,toY) <- readIORef toVar
writeIORef fromVar (fromX+addX, fromY+addY)
writeIORef toVar (toX+addX, toY+addY)
return $ Figure { draw=drawF, move=moveF }
Now we can test the code which moves figures around:
main = do figures <- sequence [circle (10,10) 5,
rectangle (10,10) (20,20)]
drawAll figures
mapM_ (\fig -> move fig (10,10)) figures
drawAll figures
It's important to realize that we are not limited to including only I/O actions
in a record that's intended to simulate a C++/Java-style interface. The record
can also include values, IORef
s, pure functions - in short, any
type of data. For example, we can easily add to the Figure
interface fields for area and origin:
data Figure = Figure { draw :: IO (),
move :: Displacement -> IO (),
area :: Double,
origin :: IORef Point
}
Exception handling (under development)
Although Haskell provides a set of exception raising/handling features comparable to those in popular OOP languages (C++, Java, C#), this part of the language receives much less attention. This is for two reasons:
- you just don't need to worry as much about them - most of the time it just works "behind the scenes".
- Haskell, lacking OOP-style inheritance, doesn't allow the programmer to easily subclass exception types, therefore limiting the flexibility of exception handling.
Haskell can raise more exceptions than other programming languages - pattern
match failures, calls with invalid arguments (such as
head []
) and computations
whose results depend on special values undefined
and
error "...."
all raise
their own exceptions:
- example 1:
main = print (f 2) f 0 = "zero" f 1 = "one"
- example 2:
main = print (head [])
- example 3:
main = print (1 + (error "Value that wasn't initialized or cannot be computed"))
This allows the writing of programs in a much more error-prone way.
Interfacing with C/C++ and foreign libraries (under development)
While Haskell is great at algorithm development, speed isn't its best side. We can combine the best of both languages, though, by writing speed-critical parts of program in C and the rest in Haskell. We just need a way to call C routines from Haskell and vice versa, and to marshal data between the two languages.
We also need to interact with C to use Windows/Linux APIs, linking to various libraries and DLLs. Even interfacing with other languages often requires going through C, which acts as a "common denominator". Chapter 8 of the Haskell 2010 report provides a complete description of interfacing with C.
We will learn to use the FFI via a series of examples. These examples include C/C++ code, so they need C/C++ compilers to be installed, the same will be true if you need to include code written in C/C++ in your program (C/C++ compilers are not required when you just need to link with existing libraries providing APIs with C calling convention). On Unix (and Mac OS?) systems, the system-wide default C/C++ compiler is typically used by GHC installation. On Windows, no default compilers exist, so GHC is typically shipped with a C compiler, and you may find on the download page a GHC distribution bundled with C and C++ compilers. Alternatively, you may find and install a GCC/MinGW version compatible with your GHC installation.
If you need to make your C/C++ code as fast as possible, you may compile your code by Intel compilers instead of GCC. However, these compilers are not free, moreover on Windows, code compiled by Intel compilers may not interact correctly with GHC-compiled code, unless one of them is put into DLLs (due to object file incompatibility).
- C->Haskell
- A lightweight tool for implementing access to C libraries from Haskell.
- HSFFIG
- The Haskell FFI Binding Modules Generator (HSFFIG) is a tool that takes a C library header (".h") and generates Haskell Foreign Function Interface import declarations for items (functions, structures, etc.) the header defines.
- MissingPy
- MissingPy is really two libraries in one. At its lowest level, MissingPy is a library designed to make it easy to call into Python from Haskell. It provides full support for interpreting arbitrary Python code, interfacing with a good part of the Python/C API, and handling Python objects. It also provides tools for converting between Python objects and their Haskell equivalents. Memory management is handled for you, and Python exceptions get mapped to Haskell
Dynamic
exceptions. At a higher level, MissingPy contains Haskell interfaces to some Python modules.
- HsLua
- A Haskell interface to the Lua scripting language
Foreign calls
We begin by learning how to call C routines from Haskell and Haskell definitions from C. The first example consists of three files:
main.hs:
{-# LANGUAGE ForeignFunctionInterface #-}
main = do print "Hello from main"
c_routine
haskell_definition = print "Hello from haskell_definition"
foreign import ccall safe "prototypes.h"
c_routine :: IO ()
foreign export ccall
haskell_definition :: IO ()
vile.c:
#include <stdio.h>
#include "prototypes.h"
void c_routine (void)
{
printf("Hello from c_routine\n");
haskell_definition();
}
prototypes.h:
extern void c_routine (void);
extern void haskell_definition (void);
It may be compiled and linked in one step by ghc:
ghc --make main.hs vile.c
Or, you may compile C module(s) separately and link in ".o" files (this may be
preferable if you use make
and don't want to recompile unchanged
sources; ghc's --make
option provides smart recompilation only for
".hs" files):
ghc -c vile.c ghc --make main.hs vile.o
You may use gcc/g++ directly to compile your C/C++ files but I recommend to do
linking via ghc because it adds a lot of libraries required for execution of
Haskell code. For the same reason, even if main
in your program is
written in C/C++, I recommend calling it from the Haskell action main
-
otherwise you'll have to explicitly init/shutdown the GHC RTS (run-time system).
We use the foreign import
declaration to import foreign routines
into Haskell, and foreign export
to export Haskell definitions
"outside" for imperative languages to use. Note that import
creates a new Haskell symbol (from the external one), while export
uses a Haskell symbol previously defined. Technically speaking, both types of
declarations create a wrapper that converts the names and calling conventions
from C to Haskell or vice versa.
All about the foreign
declaration
The ccall
specifier in foreign declarations means the use of the C
(not C++ !) calling convention. This means that if you want to write the
external routine in C++ (instead of C) you should add export "C"
specification to its declaration - otherwise you'll get linking errors. Let's
rewrite our first example to use C++ instead of C:
prototypes.h:
#ifdef __cplusplus
extern "C" {
#endif
extern void c_routine (void);
extern void haskell_definition (void);
#ifdef __cplusplus
}
#endif
Compile it via:
ghc --make main.hs vile.cpp
where "vile.cpp" is just a renamed copy of "vile.c" from the first example.
Note that the new "prototypes.h" is written to allow compiling it both as C and
C++ code. When it's included from "vile.cpp", it's compiled as C++ code. When
GHC compiles "main.hs" via the C compiler (enabled by the -fvia-C
option), it also includes "prototypes.h" but compiles it in C mode. It's why
you need to specify ".h" files in foreign
declarations - depending
on which Haskell compiler you use, these files may be included to check
consistency of C and Haskell declarations.
The quoted part of the foreign declaration may also be used to give the import or export another name - for example,
foreign import ccall safe "prototypes.h CRoutine"
c_routine :: IO ()
foreign export ccall "HaskellDefinition"
haskell_definition :: IO ()
specifies that:
- the C routine called
CRoutine
will become known asc_routine
in Haskell, - while the Haskell definition
haskell_definition
will be known asHaskellDefinition
in C.
It's required when the C name doesn't conform to Haskell naming requirements.
Although the Haskell FFI standard tells about many other calling conventions in
addition to ccall
(e.g. cplusplus
, jvm
,
net
) current Haskell implementations support only ccall
and stdcall
. The latter, also called the "Pascal" calling
convention, is used to interface with WinAPI:
foreign import stdcall unsafe "windows.h SetFileApisToOEM"
setFileApisToOEM :: IO ()
And finally, about the safe
/unsafe
specifier: a C
routine imported with the unsafe
keyword is called directly and
the Haskell runtime is stopped while the C routine is executed (when there are
several OS threads executing the Haskell program, only the current OS thread is
delayed). This call doesn't allow recursively entering back into Haskell by
calling any Haskell definition - the Haskell RTS is just not prepared for such
an event. However, unsafe
calls are as quick as calls in C. It's
ideal for "momentary" calls that quickly return back to the caller.
When safe
is specified, the C routine is called in a safe
environment - the Haskell execution context is saved, so it's possible to call
back to Haskell and, if the C call takes a long time, another OS thread may be
started to execute Haskell code (of course, in threads other than the one that
called the C code). This has its own price, though - around 1000 CPU ticks per
call.
You can read more about interaction between FFI calls and Haskell concurrency in [7].
Marshalling simple types
Calling by itself is relatively easy; the real problem of interfacing languages
with different data models is passing data between them. In this case, there is
no guarantee that Haskell's Int
is represented in memory the same
way as C's int
, nor Haskell's Double
the same as C's
double
and so on. While on some platforms they are the same
and you can write throw-away programs relying on these, the goal of portability
requires you to declare foreign imports and exports using special types
described in the FFI standard, which are guaranteed to correspond to C types.
These are:
import Foreign.C.Types ( -- equivalent to the following C type:
CChar, CUChar, -- char/unsigned char
CShort, CUShort, -- short/unsigned short
CInt, CUInt, CLong, CULong, -- int/unsigned/long/unsigned long
CFloat, CDouble...) -- float/double
Now we can typefully import and export to and from C and Haskell:
foreign import ccall unsafe "math.h"
c_sin :: CDouble -> CDouble
Note that C routines which behave like pure functions (those whose
results depend only on their arguments) are imported without IO
in their return type. The const
specifier in C is not reflected
in Haskell types, so appropriate compiler checks are not performed.
All these numeric types are instances of the same classes as their Haskell
cousins (Ord
, Num
, Show
and so on), so
you may perform calculations on these data directly. Alternatively, you may
convert them to native Haskell types. It's very typical to write simple
wrappers around foreign imports and exports just to provide interfaces having
native Haskell types:
-- |Type-conversion wrapper around c_sin
sin :: Double -> Double
sin = fromRational . c_sin . toRational
Memory management
Marshalling strings
import Foreign.C.String ( -- representation of strings in C
CString, -- = Ptr CChar
CStringLen) -- = (Ptr CChar, Int)
foreign import ccall unsafe "string.h"
c_strlen :: CString -> IO CSize -- CSize defined in Foreign.C.Types and is equal to size_t
-- |Type-conversion wrapper around c_strlen
strlen :: String -> Int
strlen = ....
Marshalling composite types
A C array may be manipulated in Haskell as StorableArray.
There is no built-in support for marshalling C structures and using C constants in Haskell. These are implemented in the c2hs preprocessor, though.
Binary marshalling (serializing) of data structures of any complexity is implemented in the library module "Binary".
Dynamic calls
DLLs
because i don't have experience of using DLLs, can someone write into this section? Ultimately, we need to consider the following tasks:
- using DLLs of 3rd-party libraries (such as ziplib)
- putting your own C code into a DLL to use in Haskell
- putting Haskell code into a DLL which may be called from C code
The dark side of the I/O monad
Unless you are a systems developer, postgraduate CS student, or have alternate (and eminent!) verifiable qualifications you should have no need whatsoever for this section - here is just one tiny example of what can go wrong if you don't know what you are doing. Look for other solutions!
unsafePerformIO
Do you remember this definition?
getChar >>= \c -> c
Let's try to "define" something with it:
getchar :: Char
getchar = getChar >>= \c -> c
get2chars :: String
get2chars = [a, b] where a = getchar
b = getchar
But what makes all of that so wrong? Besides getchar
and get2chars
not being I/O actions:
- Because the Haskell compiler treats all functions as pure (not having side effects), it can avoid "unnecessary" calls to
getchar
and use one returned value twice; - Even if it does make two calls, there is no way to determine which call should be performed first. Do you want to return the two characters in the order in which they were read, or in the opposite order? Nothing in the definition of
get2chars
answers this question.
Despite these problems, programmers coming from an imperative language background often look for a way to do this - disguise one or more I/O actions as a pure definition. Having seen procedural entities similar in appearance to:
void putchar(char c);
the thought of just writing:
putchar :: Char -> ()
putchar c = ...
would definitely be more appealing - for example, defining
readContents
as though it were a pure function:
readContents :: Filename -> String
will certainly simplify the code that uses it. However, those exact same problems are also lurking here:
- Attempts to read the contents of files with the same name can be factored (i.e. reduced to a single call) despite the fact that the file (or the current directory) can be changed between calls. Haskell considers all non-
IO
functions to be pure and feels free to merge multiple calls with the same parameters. - This call is not inserted in a sequence of I/O actions all the way from
main
so the compiler doesn't know at what exact moment you want to execute this action. For example, if the file has one kind of contents at the beginning of the program and another at the end - which contents do you want to see? You have no idea when (or even if) this function is going to get invoked, because Haskell sees this function as pure and feels free to reorder the execution of any or all pure functions as needed.
So, implementing supposedly-pure functions that interact with the Real World
is considered to be Bad Behavior. Nice programmers never do it ;-)
Nevertheless, there are (semi-official) ways to use I/O actions inside of pure functions - there is a (ahem) "special" definition that will (mis)use the Haskell implementation to run an I/O action. This particular (and dangerous) is:
unsafePerformIO :: IO a -> a
Using unsafePerformIO
, you could easily write "pure-looking
functions" that actually do I/O inside. But don't do this without a real need,
and remember to follow this rule:
- the compiler doesn't know that you are cheating; it still considers each non-
IO
function to be a pure one. Therefore, all the usual optimization rules can (and will!) be applied to its execution.
So you must ensure that:
- The result of each call depends only on its arguments.
- You don't rely on side-effects of this function, which may be not executed if its results are not needed.
Let's investigate this problem more deeply. Function evaluation in Haskell is
determined by a value's necessity - the language computes only the values that
are really required to calculate the final result. But what does this mean with
respect to the main
action? To run it to completion, all the
intermediate I/O actions that are included in main
's chain need to
be run. By using unsafePerformIO
we call I/O actions outside of this
chain. What guarantee do we have that they will be run at all? None. The only
time they will be run is if running them is required to compute the overall
function result (which in turn should be required to perform some action in the
main
chain). This is an example of Haskell's evaluation-by-need
strategy. Now you should clearly see the difference:
- An I/O action inside an I/O definition is guaranteed to execute as long as it is (directly or indirectly) inside the
main
chain - even when its result isn't used (because it will be run anyway). You directly specify the order of the action's execution inside the I/O definition.
- An I/O action called by
unsafePerformIO
will be performed only if its result is really used. The evaluation order is not guaranteed and you should not rely on it (except when you're sure about whatever data dependencies may exist).
I should also say that inside the unsafePerformIO
call you can
organize a small internal chain of I/O actions with the help of the same
binding operators and/or do
syntactic sugar we've seen above. So
here's how we'd rewrite our previous (pure!) definition of one
using unsafePerformIO
:
one :: Integer
one = unsafePerformIO $ do var <- newIORef 0
modifyIORef var (+1)
readIORef var
and in this case all the I/O actions in this chain will be run when
the result of the unsafePerformIO
call is needed.
inlinePerformIO
The internal code for inlinePerformIO
is similar to that of
unsafePerformIO
, sometimes having an INLINE
pragma.
Semantically inlinePerformIO = unsafePerformIO
in as
much as either of those have any semantics at all.
The difference of course is that inlinePerformIO
is even less safe
than unsafePerformIO
. While ghc will try not to duplicate or
common up different uses of unsafePerformIO
, we aggressively
inline inlinePerformIO
. So you can really only use it where the
I/O content is really properly pure, like reading from an immutable memory
buffer (as in the case of ByteString
s). However things like
allocating new buffers should not be done inside inlinePerformIO
since that can easily be floated out and performed just once for the whole
program, so you end up with many things sharing the same buffer, which would
be bad.
So the rule of thumb is that I/O actions wrapped in unsafePerformIO
have to be externally pure while with inlinePerformIO
it has
to be really, really pure or it'll all go horribly wrong.
That said, here's some really hairy code. This should frighten any pure functional programmer...
write :: Int -> (Ptr Word8 -> IO ()) -> Put ()
write !n body = Put $ \c buf@(Buffer fp o u l) ->
if n <= l
then write</code> c fp o u l
else write</code> (flushOld c n fp o u) (newBuffer c n) 0 0 0
where {-# NOINLINE write</code> #-}
write</code> c !fp !o !u !l =
-- warning: this is a tad hardcore
inlinePerformIO
(withForeignPtr fp
(\p -> body $! (p `plusPtr` (o+u))))
`seq` c () (Buffer fp o (u+n) (l-n))
it's used like:
word8 w = write 1 (\p -> poke p w)
This does not adhere to my rule of thumb above. Don't ask exactly why we claim
it's safe :-)
(and if anyone really wants to know, ask Ross Paterson who did it
first in the Builder
monoid)
unsafeInterleaveIO
But there is an even stranger operation:
unsafeInterleaveIO :: IO a -> IO a
and here's one clear reason why:
{-# NOINLINE unsafeInterleaveIO #-}
unsafeInterleaveIO :: IO a -> IO a
unsafeInterleaveIO a = return (unsafePerformIO a)
So don't let that type signature fool you - unsafeInterleaveIO
also has to be used carefully! It too sets up its unsuspecting parameter to
run lazily, instead of running in the main
action chain, with the
only difference being the result of running the parameter can only be used
by another I/O action. But this is of little benefit - ideally the parameter
and the main
action chain should have no other interactions with
each other, otherwise things can get ugly!
At least you have some appreciation as to why unsafeInterleaveIO
is, well unsafe! Just don't ask - to talk further is bound to cause grief
and indignation. I won't say anything more about this ruffian I...use all the
time (darn it!)
One can use unsafePerformIO
(not unsafeInterleaveIO
)
to perform I/O operations not in some predefined order but by demand. For
example, the following code:
do let c = unsafePerformIO getChar
do_proc c
will perform the getChar
I/O call only when the value of
c
is really required by the calling code, i.e. it this call will
be performed lazily like any regular Haskell computation.
Now imagine the following code:
do let s = [unsafePerformIO getChar, unsafePerformIO getChar, unsafePerformIO getChar]
do_proc s
The three characters inside this list will be computed on demand too, and this means that their values will depend on the order they are consumed. It is not what we usually want.
unsafeInterleaveIO
solves this problem - it performs I/O only on
demand but allows you to define the exact internal execution order for
parts of your data structure.
unsafeInterleaveIO
accepts an I/O action as a parameter and returns another I/O action as the result:
do str <- unsafeInterleaveIO myGetContents ⋮
unsafeInterleaveIO
doesn't perform any action immediately, it only creates a closure of typea
which upon being needed will perform the action specified as the parameter.
- this action by itself may compute the whole value immediately...or use
unsafeInterleaveIO
again to defer calculation of some sub-components:
myGetContents = do c <- getChar s <- unsafeInterleaveIO myGetContents return (c:s)
This code will be executed only at the moment when the value of str
is really demanded. In this moment, getChar
will be performed
(with its result assigned to c
) and a new lazy-I/O closure will be
created - for s
. This new closure also contains a link to a
myGetContents
call.
The resulting list is then returned. It contains the Char
that was
just read and a link to another myGetContents
call as a way to
compute the rest of the list. Only at the moment when the next value in the
list is required will this operation be performed again.
As a final result, we can postpone the read of the second Char
in
the list before the first one, but have lazy reading of characters as a whole -
bingo!
PS: of course, actual code should include EOF checking; also note that you can
read multiple characters/records at each call:
myGetContents = do
l <- replicateM 512 getChar
s <- unsafeInterleaveIO myGetContents
return (l++s)
and we can rewrite myGetContents
to avoid needing to use
unsafeInterleaveIO
where it's called:
myGetContents = unsafeInterleaveIO $ do
l <- replicateM 512 getChar
s <- myGetContents
return (l++s)
Welcome to the machine: taking off the covers
A little disclaimer: I should say that I'm not describing here exactly what a monad is (I don't even completely understand it myself) and my explanation shows only one possible way to implement the I/O monad in Haskell. For example, the hbc compiler and the Hugs interpreter implements the I/O monad via continuations [9]. I also haven't said anything about exception handling, which is a natural part of the "monad" concept. You can read the All About Monads guide to learn more about these topics.
But there is some good news: the I/O monad understanding you've just acquired will work with any implementation and with many other monads.
The GHC implementation
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
It uses the State# RealWorld
type and the strict tuple type
(# ... #)
for optimization. It also uses an IO
data
constructor. Nevertheless, there are no significant changes from the standpoint
of our explanation.
Of course, other compilers e.g. yhc/nhc (jhc, too?) define IO
in
other ways.
The Yhc/nhc98 implementation
data World = World
newtype IO a = IO (World -> Either IOError a)
This implementation makes the World
disappear somewhat[10],
and returns Either
a result of type a
, or if an error
occurs then IOError
. The lack of the World
on the
right-hand side of the function can only be done because the compiler knows
special things about the IO
type, and won't overoptimise it.
Further reading
[1] This manual is largely based on Simon Peyton Jones's paper Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell. I hope that my manual improves his original explanation of the Haskell I/O system and brings it closer to the point of view of new Haskell programmers. But if you need to learn about concurrency, exceptions and the FFI in Haskell/GHC, the original paper is the best source of information.
[2] You can find more information about concurrency, the FFI and STM at the GHC/Concurrency#Starting points page.
[3] The Arrays page contains exhaustive explanations about using mutable arrays.
[4] Look also at the Using monads page, which contains tutorials and papers really describing these mysterious monads.
[5] An explanation of the basic monad functions, with examples, can be found in the reference guide A tour of the Haskell Monad functions, by Henk-Jan van Tuyl.
[6] Official FFI specifications can be found on the page The Haskell 98 Foreign Function Interface 1.0: An Addendum to the Haskell 98 Report
[7] Using the FFI in multithreaded programs is described in Extending the Haskell Foreign Function Interface with Concurrency
[8] This particular behaviour is not a requirement of Haskell 2010, so the operation of seq
may differ between various Haskell implementations - if you're not sure, staying within the I/O monad is the safest option.
[9] How to Declare an Imperative by Phil Wadler provides an explanation of how this can be done.
Do you have more questions? Ask in the haskell-cafe mailing list.
To-do list
If you are interested in adding more information to this manual, please add your questions/topics here.
Topics:
fixIO
andmdo
Q
monad
Questions:
- split
(>>=)
/(>>)
/return
section anddo
section, more examples of using binding operators IORef
detailed explanation (==const*
), usage examples, syntax sugar, unboxed refs- explanation of how the actual data "in" mutable references are inside GHC's
RealWorld
, rather than inside the references themselves (IORef
,IOArray
& co.) - control structures developing - much more examples
unsafePerformIO
usage examples: global variable,ByteString
, other examples- how
unsafeInterLeaveIO
can be seen as a kind of concurrency, and therefore isn't so unsafe (unlikeunsafeInterleaveST
which really is unsafe) - discussion about different senses of
safe
/unsafe
(like breaking equational reasoning vs. invoking undefined behaviour (so can corrupt the run-time system)) - actual code used by GHC - how to write low-level definitions based on example of how
newIORef
is implemented
This manual is collective work, so feel free to add more information to it yourself. The final goal is to collectively develop a comprehensive manual for using the I/O monad.