Haskell function with type IO Int -> Int, without using unsafePerformIO - haskell

I have a homework question asking me:
Can you write a Haskell function with type IO Int -> Int (without using unsafePerformIO)? If yes, give the function; if not, explain the reason.
I have tried to write such a function:
test :: IO Int -> Int
test a = do
x <- a
return x
But this does not work. I have tried to make it work for a while, and I can't, so I gather that the answer to the question is no. But, I do not understand why it is not possible. Why doesn't it work?

The only functions of type IO Int -> Int are uninteresting, since they must ignore their argument. that is, they must be equivalent to
n :: Int
n = ...
f :: IO Int -> Int
f _ = n
(Technically, there's also f x = x `seq` n, as #Keshav points out).
This is because there's no way to escape the IO monad (unlike most other monads). This is by design. Consider
getInt :: IO Int
getInt = fmap read getLine
which is a function which reads an integer from stdin. If we could write
n :: Int
n = f getInt
this would be an integer value which can "depend" on the IO action getInt... but must be pure, i.e. must do no IO at all. How can we use an IO action if we must do no IO at all? It turns out that we can not use it in any way.
The only way to do such operation meaningfully is to allow the programmer break the "purity" contract, which is the main thing behind Haskell. GHC gives the programmer a few "unsafe" operations if the programmer is bold enough to declare "trust me, I know what I am doing". One of them is "unsafePerformIO". Another is accessing the realWorld# low-level stuff in GHC.* modules (as #Michael shows above). Even the FFI can import a C function claiming it to be pure, essentially enabling the user to write their own unsafePerformIO.

Well, there are two ways...
If you are happy with a constant function, use this:
test :: IO Int -> Int
test a = 42
Otherwise, you have to do the same thing that unsafePerformIO does (or more specifically unsafeDupablePerformIO).
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
import GHC.Base (IO(..), realWorld#)
unIO (IO m) = case m realWorld# of (# _, r #) -> r
test :: IO Int -> Int
test a = (unIO a) + 1
Have fun...
Disclaimer: this is all really hacky ;)

Related

Modeling a domain as a GADT type and providing do-sugar for it

Assume we'd like to build a type that represents operations typical for, let's say, a lock-free algorithm:
newtype IntPtr = IntPtr { ptr :: Int } deriving (Eq, Ord, Show)
data Op r where
OpRead :: IntPtr -> Op Int
OpWrite :: IntPtr -> Int -> Op ()
OpCAS :: IntPtr -> Int -> Int -> Op Bool
Ideally, we'd like to represent some algorithms within this model using a convenient do-notation, like (assuming corresponding read = OpRead and cas = OpCAS for aesthetic reasons) the following almost literal translation of the Wikipedia example:
import Prelude hiding (read)
import Control.Monad.Loops
add :: IntPtr -> Int -> Op Int
add p a = snd <$> do
iterateUntil fst $ do
value <- read p
success <- cas p value (value + a)
pure (success, value + a)
How could we achieve that? Let's add a couple more constructors to Op to represent pure injected values and the monadic bind:
OpPure :: a -> Op a
OpBind :: Op a -> (a -> Op b) -> Op b
So let's try to write a Functor instance. OpPure and OpBind is easy, being, for instance:
instance Functor Op where
fmap f (OpPure x) = OpPure (f x)
But the constructors that specify the GADT type start smelling bad:
fmap f (OpRead ptr) = do
val <- OpRead ptr
pure $ f val
Here we assume we'll write the Monad instance later on anyway to avoid ugly nested OpBinds.
Is this the right way to handle such types, or is my design just terribly wrong, this being a sign of it?
This style of using do-notation to build a syntax tree that'll be interpreted later is modelled by the free monad. (I'm actually going to demonstrate what's known as the freer or operational monad, because it's closer to what you have so far.)
Your original Op datatype - without OpPure and OpBind - represents a set of atomic typed instructions (namely read, write and cas). In an imperative language a program is basically a list of instructions, so let's design a datatype which represents a list of Ops.
One idea might be to use an actual list, ie type Program r = [Op r]. Clearly that won't do as it constrains every instruction in the program to have the same return type, which would not make for a very useful programming language.
The key insight is that in any reasonable operational semantics of an interpreted imperative language, control flow doesn't proceed past an instruction until the interpreter has computed a return value for that instruction. That is, the nth instruction of a program depends in general on the results of instructions 0 to n-1. We can model this using continuation passing style.
data Program a where
Return :: a -> Program a
Step :: Op r -> (r -> Program a) -> Program a
A Program is a kind of list of instructions: it's either an empty program which returns a single value, or it's a single instruction followed by a list of instructions. The function inside the Step constructor means that the interpreter running the Program has to come up with an r value before it can resume interpreting the rest of the program. So sequentiality is ensured by the type.
To build your atomic programs read, write and cas, you need to put them in a singleton list. This involves putting the relevant instruction in the Step constructor, and passing a no-op continuation.
lift :: Op a -> Program a
lift i = Step i Return
read ptr = lift (OpRead ptr)
write ptr val = lift (OpWrite ptr val)
cas ptr cmp val = lift (OpCas ptr cmp val)
Program differs from your tweaked Op in that at each Step there's only ever one instruction. OpBind's left argument was potentially a whole tree of Ops. This would've allowed you to distinguish differently-associated >>=s, breaking the monad associativity law.
You can make Program a monad.
instance Monad Program where
return = Return
Return x >>= f = f x
Step i k >>= f = Step i ((>>= f) . k)
>>= basically performs list concatenation - it walks to the end of the list (by composing recursive calls to itself under the Step continuations) and grafts on a new tail. This makes sense - it corresponds to the intutitive "run this program, then run that program" semantics of >>=.
Noting that Program's Monad instance doesn't depend on Op, an obvious generalisation is to parameterise the type of instruction and make Program into a list of any old instruction set.
data Program i a where
Return :: a -> Program i a
Step :: i r -> (r -> Program i a) -> Program a
instance Monad (Program i) where
-- implementation is exactly the same
So Program i is a monad for free, no matter what i is. This version of Program is a rather general tool for modelling imperative languages.

Haskell: How to use random integer from randomRIO in a function that returns a boolean

I am new to Haskell and i'm having a problem with using the IO Int from randomRIO function. My goal is to get a random Int value, say r, and to return True if r < x or false otherwise, but i don't know how to do it.
my function should look like:
randomCompare :: Int->Bool
randomCompare x
| x < r = True -- somehow i want to r <- randomRIO(start,end)
| otherwise = False
I know there is a designed intention with keeping IO vals in context for purity etc.. but i don't see why using a random number for a Boolean function should be "bad".
Thanks.
import System.Random(randomIO)
randomCompare :: Int -> IO Bool
randomCompare x = do
r <- randomIO
return $ x < r
IO is neither good nor bad, it just declares that your function has side effects. Here the side effect is modifying the state of the global random number generator, so that a subsequent call to randomIO will give another number (it wouldn't be random if it was constant !).
IO does force all calling functions to be IO too (the ones that want to use the IO Bool). However, if a calling function is IO only by consuming this IO Bool, if it has no other side effects, then you can separate it as a pure function f :: Bool -> SomeType and functorially apply it on the IO, ie
f <$> randomCompare i
So the IO monad only costs you to replace the ordinary function call $ by the functorial fmap, also noted <$>. Is it so much longer to type ?
If you absolutely want to leave the IO monad (why ?), you can also draw all the random values you need first, store them in a list, then apply pure functions on that list.

Best practices for talking to an API

I'm trying to create some bindings for an API in Haskell. I noticed some functions have a tremendous number of arguments, e.g.
myApiFunction :: Key -> Account -> Int -> String -> Int -> Int -> IO (MyType)
It's not necessarily bad, per se, to have this many arguments. But as a user I don't like long argument functions. However, each of these args is absolutely 100% necessary.
Is there a more haskell-ish way to abstract over the common parts of these functions? Everything past account here is used to build a URL, so I would need it available, and what it stands for depends entirely on the function. Certain things are consistent though, like Key and Account, and I'm wondering what the best to abstract over these arguments is.
Thank you!
You can combine these into more descriptive data types:
data Config = Config
{ cKey :: Key
, cAccount :: Account
}
Then maybe have types or newtypes to make the other arguments more descriptive:
-- I have no idea what these actually should be, I'm just making up something
type Count = Int
type Name = String
type Position = (Int, Int)
myApiFunction :: Config -> Count -> Name -> Position -> IO MyType
myApiFunction conf count name (x, y) =
myPreviousApiFunction (cKey conf)
(cAccount conf)
name
name
x
y
If the Config is always needed, then I would recommend working in a Reader monad, which you can easily do as
myApiFunction
:: (MonadReader Config io, MonadIO io)
=> Count -> Name -> Position
-> io MyType
myApiFunction count name (x, y) = do
conf <- ask
liftIO $ myPreviousApiFunction
(cKey conf)
(cAccount conf)
name
name
x
y
This uses the mtl library for monad transformers. If you don't want to have to type that constraint over and over, you can also use the ConstraintKinds extension to alias it:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
...
type ApiCtx io = (MonadReader Config io, MonadIO io)
...
myApiFunction
:: ApiCtx io
=> Count -> Location -> Position
-> io MyType
myApiFunction ...
Depending on your specific application, you could also split it up into multiple function. I've seen plenty of APIs before that had something like
withCount :: ApiCtx io => Count -> io a -> io a
withName :: ApiCtx io => Name -> io a -> io a
withPos :: ApiCtx io => Position -> io a -> io a
(&) :: a -> (a -> b) -> b
request :: ApiCtx io => io MyType
> :set +m -- Multi-line input
> let r = request & withCount 1
| & withName "foo"
| & withPos (1, 2)
> runReaderT r (Config key acct)
These are just a handful of techniques, there are others out there as well but they generally start becoming more complex after this. Others will have different preferences on how to do this, and I'm sure plenty would disagree with me on whether some of these are even good practice (specifically ConstraintKinds, it isn't universally accepted).
If you find yourself having type signatures that are too large a lot, even after applying some of these techniques, then maybe you're approaching the problem from the wrong direction, maybe those functions can be broken down into simpler intermediate steps, maybe some of those arguments can be grouped together logically into more specific data types, maybe you just need a larger record structure to handle setting up complex operations. It's pretty open ended right now.

When is unsafeInterleaveIO unsafe?

Unlike other unsafe* operations, the documentation for unsafeInterleaveIO is not very clear about its possible pitfalls. So exactly when is it unsafe? I would like to know the condition for both parallel/concurrent and the single threaded usage.
More specifically, are the two functions in the following code semantically equivalent? If not, when and how?
joinIO :: IO a -> (a -> IO b) -> IO b
joinIO a f = do !x <- a
!x' <- f x
return x'
joinIO':: IO a -> (a -> IO b) -> IO b
joinIO' a f = do !x <- unsafeInterleaveIO a
!x' <- unsafeInterleaveIO $ f x
return x'
Here's how I would use this in practice:
data LIO a = LIO {runLIO :: IO a}
instance Functor LIO where
fmap f (LIO a) = LIO (fmap f a)
instance Monad LIO where
return x = LIO $ return x
a >>= f = LIO $ lazily a >>= lazily . f
where
lazily = unsafeInterleaveIO . runLIO
iterateLIO :: (a -> LIO a) -> a -> LIO [a]
iterateLIO f x = do
x' <- f x
xs <- iterateLIO f x' -- IO monad would diverge here
return $ x:xs
limitLIO :: (a -> LIO a) -> a -> (a -> a -> Bool) -> LIO a
limitLIO f a converged = do
xs <- iterateLIO f a
return . snd . head . filter (uncurry converged) $ zip xs (tail xs)
root2 = runLIO $ limitLIO newtonLIO 1 converged
where
newtonLIO x = do () <- LIO $ print x
LIO $ print "lazy io"
return $ x - f x / f' x
f x = x^2 -2
f' x = 2 * x
converged x x' = abs (x-x') < 1E-15
Although I would rather avoid using this code in serious applications because of the terrifying unsafe* stuff, I could at least be lazier than would be possible with the stricter IO monad in deciding what 'convergence' means, leading to (what I think is) more idiomatic Haskell. And this brings up another question:why is it not the default semantics for Haskell's (or GHC's?) IO monad? I've heard some resource management issues for lazy IO (which GHC only provides by a small fixed set of commands), but the examples typically given somewhat resemble like a broken makefile:a resource X depends on a resource Y, but if you fail to specify the dependency, you get an undefined status for X. Is lazy IO really the culprit for this problem? (On the other hand, if there is a subtle concurrency bug in the above code such as deadlocks I would take it as a more fundamental problem.)
Update
Reading Ben's and Dietrich's answer and his comments below, I have briefly browsed the ghc source code to see how the IO monad is implemented in GHC. Here I summerize my few findings.
GHC implements Haskell as an impure, non-referentially-transparent language. GHC's runtime operates by successively evaluating impure functions with side effects just like any other functional languages. This is why the evaluation order matters.
unsafeInterleaveIO is unsafe because it can introduce any kind of concurrency bugs even in a sigle-threaded program by exposing the (usually) hidden impurity of GHC's Haskell. (iteratee seems to be a nice and elegant solution for this, and I will certainly learn how to use it.)
the IO monad must be strict because a safe, lazy IO monad would require a precise (lifted) representation of the RealWorld, which seems impossible.
It's not just the IO monad and unsafe functions that are unsafe. The whole Haskell (as implemented by GHC) is potentially unsafe, and 'pure' functions in (GHC's) Haskell are only pure by convention and the people's goodwill. Types can never be a proof for purity.
To see this, I demonstrate how GHC's Haskell is not referentially transparent regardless of the IO monad, regardless of the unsafe* functions,etc.
-- An evil example of a function whose result depends on a particular
-- evaluation order without reference to unsafe* functions or even
-- the IO monad.
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE BangPatterns #-}
import GHC.Prim
f :: Int -> Int
f x = let v = myVar 1
-- removing the strictness in the following changes the result
!x' = h v x
in g v x'
g :: MutVar# RealWorld Int -> Int -> Int
g v x = let !y = addMyVar v 1
in x * y
h :: MutVar# RealWorld Int -> Int -> Int
h v x = let !y = readMyVar v
in x + y
myVar :: Int -> MutVar# (RealWorld) Int
myVar x =
case newMutVar# x realWorld# of
(# _ , v #) -> v
readMyVar :: MutVar# (RealWorld) Int -> Int
readMyVar v =
case readMutVar# v realWorld# of
(# _ , x #) -> x
addMyVar :: MutVar# (RealWorld) Int -> Int -> Int
addMyVar v x =
case readMutVar# v realWorld# of
(# s , y #) ->
case writeMutVar# v (x+y) s of
s' -> x + y
main = print $ f 1
Just for easy reference, I collected some of the relevant definitions
for the IO monad as implemented by GHC.
(All the paths below are relative to the top directory of the ghc's source repository.)
-- Firstly, according to "libraries/base/GHC/IO.hs",
{-
The IO Monad is just an instance of the ST monad, where the state is
the real world. We use the exception mechanism (in GHC.Exception) to
implement IO exceptions.
...
-}
-- And indeed in "libraries/ghc-prim/GHC/Types.hs", We have
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
-- And in "libraries/base/GHC/Base.lhs", we have the Monad instance for IO:
data RealWorld
instance Functor IO where
fmap f x = x >>= (return . f)
instance Monad IO where
m >> k = m >>= \ _ -> k
return = returnIO
(>>=) = bindIO
fail s = failIO s
returnIO :: a -> IO a
returnIO x = IO $ \ s -> (# s, x #)
bindIO :: IO a -> (a -> IO b) -> IO b
bindIO (IO m) k = IO $ \ s -> case m s of (# new_s, a #) -> unIO (k a) new_s
unIO :: IO a -> (State# RealWorld -> (# State# RealWorld, a #))
unIO (IO a) = a
-- Many of the unsafe* functions are defined in "libraries/base/GHC/IO.hs":
unsafePerformIO :: IO a -> a
unsafePerformIO m = unsafeDupablePerformIO (noDuplicate >> m)
unsafeDupablePerformIO :: IO a -> a
unsafeDupablePerformIO (IO m) = lazy (case m realWorld# of (# _, r #) -> r)
unsafeInterleaveIO :: IO a -> IO a
unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m)
unsafeDupableInterleaveIO :: IO a -> IO a
unsafeDupableInterleaveIO (IO m)
= IO ( \ s -> let
r = case m s of (# _, res #) -> res
in
(# s, r #))
noDuplicate :: IO ()
noDuplicate = IO $ \s -> case noDuplicate# s of s' -> (# s', () #)
-- The auto-generated file "libraries/ghc-prim/dist-install/build/autogen/GHC/Prim.hs"
-- list types of all the primitive impure functions. For example,
data MutVar# s a
data State# s
newMutVar# :: a -> State# s -> (# State# s,MutVar# s a #)
-- The actual implementations are found in "rts/PrimOps.cmm".
So, for example, ignoring the constructor and assuming referential transparency,
we have
unsafeDupableInterleaveIO m >>= f
==> (let u = unsafeDupableInterleaveIO)
u m >>= f
==> (definition of (>>=) and ignore the constructor)
\s -> case u m s of
(# s',a' #) -> f a' s'
==> (definition of u and let snd# x = case x of (# _,r #) -> r)
\s -> case (let r = snd# (m s)
in (# s,r #)
) of
(# s',a' #) -> f a' s'
==>
\s -> let r = snd# (m s)
in
case (# s, r #) of
(# s', a' #) -> f a' s'
==>
\s -> f (snd# (m s)) s
This is not what we would normally get from binding usual lazy state monads.
Assuming the state variable s carries some real meaning (which it does not), it looks more like a concurrent IO (or interleaved IO as the function rightly says) than a lazy IO as we would normally mean by 'lazy state monad' wherein despite the laziness the states are properly threaded by an associative operation.
I tried to implement a truely lazy IO monad, but soon realized that in order to define a lazy monadic composition for the IO datatype, we need to be able to lift/unlift the RealWorld. However this seems impossible because there is no constructor for both State# s and RealWorld. And even if that were possible, I would then have to represent the precise, functional represenation of our RealWorld which is impossible,too.
But I'm still not sure whether the standard Haskell 2010 breaks referential transparency or the lazy IO is bad in itself. At least it seems entirely possible to build a small model of the RealWorld on which the lazy IO is perfectly safe and predictable. And there might be a good enough approximation that serves many practical purposes without breaking the referential transparency.
At the top, the two functions you have are always identical.
v1 = do !a <- x
y
v2 = do !a <- unsafeInterleaveIO x
y
Remember that unsafeInterleaveIO defers the IO operation until its result is forced -- yet you are forcing it immediately by using a strict pattern match !a, so the operation is not deferred at all. So v1 and v2 are exactly the same.
In general
In general, it is up to you to prove that your use of unsafeInterleaveIO is safe. If you call unsafeInterleaveIO x, then you have to prove that x can be called at any time and still produce the same output.
Modern sentiment about Lazy IO
...is that Lazy IO is dangerous and a bad idea 99% of the time.
The chief problem that it is trying to solve is that IO has to be done in the IO monad, but you want to be able to do incremental IO and you don't want to rewrite all of your pure functions to call IO callbacks to get more data. Incremental IO is important because it uses less memory, allowing you to operate on data sets that don't fit in memory without changing your algorithms too much.
Lazy IO's solution is to do IO outside of the IO monad. This is not generally safe.
Today, people are solving the problem of incremental IO in different ways by using libraries like Conduit or Pipes. Conduit and Pipes are much more deterministic and well-behaved than Lazy IO, solve the same problems, and do not require unsafe constructs.
Remember that unsafeInterleaveIO is really just unsafePerformIO with a different type.
Example
Here is an example of a program that is broken due to lazy IO:
rot13 :: Char -> Char
rot13 x
| (x >= 'a' && x <= 'm') || (x >= 'A' && x <= 'M') = toEnum (fromEnum x + 13)
| (x >= 'n' && x <= 'z') || (x >= 'N' && x <= 'Z') = toEnum (fromEnum x - 13)
| otherwise = x
rot13file :: FilePath -> IO ()
rot13file path = do
x <- readFile path
let y = map rot13 x
writeFile path y
main = rot13file "test.txt"
This program will not work. Replacing the lazy IO with strict IO will make it work.
Links
From Lazy IO breaks purity by Oleg Kiselyov on the Haskell mailing list:
We demonstrate how lazy IO breaks referential transparency. A pure
function of the type Int->Int->Int gives different integers depending
on the order of evaluation of its arguments. Our Haskell98 code uses
nothing but the standard input. We conclude that extolling the purity
of Haskell and advertising lazy IO is inconsistent.
...
Lazy IO should not be considered good style. One of the common
definitions of purity is that pure expressions should evaluate to the
same results regardless of evaluation order, or that equals can be
substituted for equals. If an expression of the type Int evaluates to
1, we should be able to replace every occurrence of the expression with
1 without changing the results and other observables.
From Lazy vs correct IO by Oleg Kiselyov on the Haskell mailing list:
After all, what could be more against
the spirit of Haskell than a `pure' function with observable side
effects. With Lazy IO, one indeed has to choose between correctness
and performance. The appearance of such code is especially strange
after the evidence of deadlocks with Lazy IO, presented on this list
less than a month ago. Let alone unpredictable resource usage and
reliance on finalizers to close files (forgetting that GHC does not
guarantee that finalizers will be run at all).
Kiselyov wrote the Iteratee library, which was the first real alternative to lazy IO.
Laziness means that when (and whether) exactly a computation is actually carried out depends on when (and whether) the runtime implementation decides it needs the value. As a Haskell programmer you completely relinquish control over the evaluation order (except by the data dependencies inherent in your code, and when you start playing with strictness to force the runtime to make certain choices).
That's great for pure computations, because the result of a pure computation will be exactly the same whenever you do it (except that if you carry out computations that you don't actually need, you might encounter errors or fail to terminate, when another evaluation order might allow the program to terminate successfully; but all non-bottom values computed by any evaluation order will be the same).
But when you're writing IO-dependent code, evaluation order matters. The whole point of IO is to provide a mechanism for building computations whose steps depend on and affect the world outside the program, and an important part of doing that is that those steps are explicitly sequenced. Using unsafeInterleaveIO throws away that explicit sequencing, and relinquishes control of when (and whether) the IO operation is actually carried out to the runtime system.
This is unsafe in general for IO operations, because there may be dependencies between their side-effects which cannot be inferred from the data dependencies inside the program. For example, one IO action might create a file with some data in it, and another IO action might read the same file. If they're both executed "lazily", then they'll only get run when the resulting Haskell value is needed. Creating the file is probably IO () though, and it's quite possible that the () is never needed. That could mean that the read operation is carried out first, either failing or reading data that was already in the file, but not the data that should have been put there by the other operation. There's no guarantee that the runtime system will execute them in the right order. To program correctly with a system that always did this for IO you'd have to be able to accurately predict the order in which the Haskell runtime will choose to perform the various IO actions.
Treat unsafeInterlaveIO as promise to the compiler (which it cannot verify, it's just going to trust you) that it doesn't matter when the IO action is carried out, or whether it's elided entirely. This is really what all the unsafe* functions are; they provide facilities that are not safe in general, and for which safety cannot be automatically checked, but which can be safe in particular instances. The onus is on you to ensure that your use of them is in fact safe. But if you make a promise to the compiler, and your promise is false, then unpleasant bugs can be the result. The "unsafe" in the name is to scare you into thinking about your particular case and deciding whether you really can make the promise to the compiler.
Basically everything under "Update" in the question is so confused it's not even wrong, so please try to forget it when you're trying to understand my answer.
Look at this function:
badLazyReadlines :: Handle -> IO [String]
badLazyReadlines h = do
l <- unsafeInterleaveIO $ hGetLine h
r <- unsafeInterleaveIO $ badLazyReadlines h
return (l:r)
In addition to what I'm trying to illustrate: the above function also doesn't handle reaching the end of the file. But ignore that for now.
main = do
h <- openFile "example.txt" ReadMode
lns <- badLazyReadlines h
putStrLn $ lns ! 4
This will print the first line of "example.txt", because the 5th element in the list is actually the first line that's read from the file.
Your joinIO and joinIO' are not semantically equivalent. They will usually be the same, but there's a subtlety involved: a bang pattern makes a value strict, but that's all it does. Bang patterns are implemented using seq, and that does not enforce a particular evaluation order, in particular the following two are semantically equivalent:
a `seq` b `seq` c
b `seq` a `seq` c
GHC can evaluate either b or a first before returning c. Indeed, it can evaluate c first, then a and b, then return c. Or, if it can statically prove a or b are non-bottom, or that c is bottom, it doesn't have to evaluate a or b at all. Some optimisations do genuinely make use of this fact, but it doesn't come up very often in practice.
unsafeInterleaveIO, by contrast, is sensitive to all or any of those changes – it does not depend on the semantic property of how strict some function is, but the operational property of when something is evaluated. So all of the above transformations are visible to it, which is why it's only reasonable to view unsafeInterleaveIO as performing its IO non-deterministically, more or less whenever it feels appropriate.
This is, in essence, why unsafeInterleaveIO is unsafe - it is the only mechanism in normal use that can detect transformations that ought to be meaning-preserving. It's the only way you can detect evaluation, which by rights ought to be impossible.
As an aside, it's probably fair to mentally prepend unsafe to every function from GHC.Prim, and probably several other GHC. modules as well. They're certainly not ordinary Haskell.

Difficulties with 'Either e` instance of `Failure` from "failure" package

This is more or less a simplified version of the issue I'm trying to understand in my own code. I'm working with functions that are polymorphic in the Failure class from this package.
{-# LANGUAGE FlexibleContexts #-}
import Data.Maybe
import Data.Either
import Control.Failure
data FookError = FookError deriving Show
fook :: (Failure FookError m)=> Int -> m Int
fook = undefined
fooks :: (Failure FookError m)=> Int -> m Int
-- DOES NOT TYPE-CHECK:
--fooks n = return $ head $ rights $ map fook [1..]
-- OKAY:
fooks n = return $ head $ catMaybes $ map fook [1..]
You can see in the above code, that when I treat the return type of fook as Maybe Int the module compiles fine, however treating it as Either Fook Int fails.
What is going on here?
This is because, in the non-working definition of fooks, fook's type is ambiguous. When you use catMaybes, it disambiguates as Maybe Int, but when you use rights, it can be Either e Int for any e, and the compiler doesn't necessarily know which. Sure, by default the only Failure instance for Either is instance Failure e (Either e), but there's nothing stopping you defining, e.g. instance Failure String (Either Int).
If you explicitly specify the type by defining fooks as
fooks n =
return $ head $ rights $ map (fook :: Int -> Either FookError Int) [1..]
then it works fine.
However, I suspect that you're not doing what you really want here; fooks never actually uses the failure capability of the underlying monad; indeed, even if there are no non-failing results, the monadic action still succeeds and returns a value. The value just so happens to be an error, but that's still probably not what you want :)
If you want fooks to try a bunch of individual fooks in turn, and return the first one that succeeds, then something like:
fooks :: (Failure FookError m, MonadPlus m) => Int -> m Int
fooks n = foldr mplus (failure FookError) $ map fook [1..]
should do the trick. The plain Failure class by itself offers no way to recover from errors, so you need to require MonadPlus too. Note that the failure FookError here will never actually be used, since [1..] is infinite, but presumably you're planning to change the definition; say to one that actually uses n :)
Unfortunately, that isn't all! Either e doesn't have a MonadPlus instance, presumably because there's no reasonable value of mzero (although another potential problem is that mplus (Left e) (Left e') could be either Left e or Left e').
Thankfully, it's easy to define an instance for our specific type:
instance MonadPlus (Either FookError) where
mzero = failure FookError
mplus a#(Right _) _ = a
mplus (Left _) a = a
You'll need {-# LANGUAGE FlexibleInstances #-} at the top of your file to do this.

Resources