1

I'm sure it's not, but I've received the type IO FileOffset from System.Posix functions, and I can't figure out what I can do with it. It seems like it's just a rename of type COFF, which seems to be just a wrapper for Int64, and in fact when I get it in GHCI, I can see the number that the IO FileOffset corresponds to. However, I can't add it to anything else, print it out (except for through the interpreter), or even convert it to another type. It seems to be immune to show.

How can I actually use this type? I'm new to Haskell so I'm sure I'm missing something fundamental about types and possibly the documentation.

River Tam
  • 3,096
  • 4
  • 31
  • 51
  • 1
    You can pass it down to functions like `fdSeek`, unwrap it to get the underlying integer, or use it as ay other instance of `Num` and `Integral` – n. m. could be an AI Apr 07 '15 at 07:22
  • 1
    @n.m.: I think OP's confused about `IO FileOffset`, not `FileOffset`. – Zeta Apr 07 '15 at 07:23
  • 1
    I think one could generalize this question into "What's `IO a`, and how can I use it?", but at that point the question gets (possibly) too broad and any potential answer results in another monad tutorial. @OP: Have a look at monads. – Zeta Apr 07 '15 at 07:26
  • An example: http://ideone.com/AWqlJT – n. m. could be an AI Apr 07 '15 at 07:28
  • 2
    @Zeta Or rather, have a look at any number of IO tutorials that avoid the M-word. – n. m. could be an AI Apr 07 '15 at 07:33
  • 2
    http://learnyouahaskell.com/input-and-output shows how to use the `String` inside `getLine :: IO String`. You can do the same for your `IO FileOffset`. – chi Apr 07 '15 at 07:41

1 Answers1

10

As discussed in numerous other questions, like this, there is never anything you can do with an IO a value as such – except bind it in another IO computation, which eventually has to be invoked from either main or ghci. And this is not some stupid arbitrary restriction of Haskell, but reflects the fact that something like a file offset can impossibly be known without the program first going “out into the world”, doing the file operation, coming back with the result. In impure languages, this kind of thing just suddenly happens when you try to evaluate an IO “function”, but only because half a century of imperative programming has done it this way doesn't mean it's a good idea. In fact it's a cause for quite a lot of bugs in non-purely functional languages, but more importantly it makes it way harder to understand what some library function will actually do – in Haskell you only need to look at the signature, and when there's no IO in it, you can be utterly sure1 it won't do any!

Question remains: how do you actually get any “real” work done? Well, it's pretty clever. For beginners, it's probably helpful to keep to this guideline:

  • An IO action always needs to be evaluated in a do block.
  • To retrieve results from such actions, use the val <- action syntax. This can stand anywhere in a do block except at the end. It is equivalent to what procedural languages write as var val = action() or similar. If action had a type IO T, then val will have simply type T!
  • The value obtained this way can be used anywhere in the same do block below the line you've obtained it from. Quite like in procedural languages.

So if your action was, say,

findOffsetOfFirstChar :: Handle -> Char -> IO FileOffset

you can use it like this:

printOffsetOfQ :: Handle -> IO ()
printOffsetOfQ h = do
   offset <- findOffsetOfFirstChar h 'Q'
   print offset

Later on you'll learn that many of these dos arent really necessary, but for the time being it's probably easiest to use them everywhere where there's IO going on.


1Some people will now object that there is a thing called unsafePerformIO which allows you to do IO without the signature telling so, but apart from being, well, unsafe, this does not actually belong to the Haskell language but to its foreign function interface.

Community
  • 1
  • 1
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • 2
    Pointing out that `unsafePerformIO` belongs to the foreign function interface is extremely helpful. – Cirdec Apr 07 '15 at 08:14