Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: I/O and Returning From a Function

Please bear with me as I am very new to functional programming and Haskell. I am attempting to write a function in Haskell that takes a list of Integers, prints the head of said list, and then returns the tail of the list. The function needs to be of type [Integer] -> [Integer]. To give a bit of context, I am writing an interpreter and this function is called when its respective command is looked up in an associative list (key is the command, value is the function).

Here is the code I have written:

dot (x:xs) = do print x
      return xs

The compiler gives the following error message:

forth.hs:12:1:
Couldn't match expected type `[a]' against inferred type `IO [a]'
  Expected type: ([Char], [a] -> [a])
  Inferred type: ([Char], [a] -> IO [a])
In the expression: (".", dot)

I suspect that the call to print in the dot function is what is causing the inferred type to be IO [a]. Is there any way that I can ignore the return type of print, as all I need to return is the tail of the list being passed into dot.

Thanks in advance.

like image 655
Ben Siver Avatar asked Oct 30 '10 01:10

Ben Siver


People also ask

What is IO () Haskell?

IO is the way how Haskell differentiates between code that is referentially transparent and code that is not. IO a is the type of an IO action that returns an a . You can think of an IO action as a piece of code with some effect on the real world that waits to get executed.

How does return work in Haskell?

return is actually just a simple function in Haskell. It does not return something. It wraps a value into a monad. Looks like return is an overloaded function.

Which function is used for output in Haskell?

The print function outputs a value of any printable type to the standard output device. Printable types are those that are instances of class Show; print converts values to strings for output using the show operation and adds a newline.


2 Answers

In most functional languages, this would work. However, Haskell is a pure functional language. You are not allowed to do IO in functions, so the function can either be

  1. [Int] -> [Int] without performing any IO or
  2. [Int] -> IO [Int] with IO

The type of dot as inferred by the compiler is dot :: (Show t) => [t] -> IO [t] but you can declare it to be [Int] -> IO [Int]:

dot :: [Int] -> IO [Int]

See IO monad: http://book.realworldhaskell.org/read/io.html


I haven't mentioned System.IO.Unsafe.unsafePerformIO that should be used with great care and with a firm understanding of its consequences.

like image 120
gawi Avatar answered Oct 07 '22 00:10

gawi


No, either your function causes side effects (aka IO, in this case printing on the screen), or it doesn't. print does IO and therefore returns something in IO and this can not be undone.

And it would be a bad thing if the compiler could be tricked into forgetting about the IO. For example if your [Integer] -> [Integer] function is called several times in your program with the same parameters (like [] for example), the compiler might perfectly well just execute the function only once and use the result of that in all the places where the function got "called". Your "hidden" print would only be executed once even though you called the function in several places.

But the type system protects you and makes sure that all function that use IO, even if only indirectly, have an IO type to reflect this. If you want a pure function you cannot use print in it.

like image 45
sth Avatar answered Oct 07 '22 00:10

sth