On Fri, 5 Nov 1999, Dusan Kolar wrote:
> Hi,
>
> Could anyone, please, give me reference to or a sophisticated
> answer?
>
> I am going to have maybe a very stupid question.
Well. it's definitely a FAQ.
> Playing with IO monads I made to me a task. Create
> a function which counts lines of a file and returns the
> number of lines as a result:
>
> lineNo :: String -> Int
> fname number of lines
>
The thing is, this *is not* a function. A function is something that
uniquely maps its arguments to values. The program you want is dependent,
not only on the fname argument, but also on the contents of a file. To
mark that the result has this dependency, you write IO in front of it. So
the function you want to write *has* the type:
lineNo :: String -> IO Int
> To access files I'm using standard file access and operators
> defined in class Monad. The problem is, that when I count
> the lines, I'm imprisoned by IO monad. Is there any way
> (e.g. by converting value to String and obtaining this string as a result)
> how to break IO monads? How to make a function of type
>
> f :: IO [Char] -> [Char]
>
Is there any way to make the function you want to write not dependent of
the contents of a file? This question and yours have the same answer.
> I know, that usually it is possible to write whole the
> program such a way so that it would not matter to have
> a IO monad as a top type, but having a function which counts number
> of lines in the file (or watever else) is also not too bad,
> at least as fas as I think, but maybe I'm completely wrong.
>
Well, you could define a function
lineNo' :: String -> Int
fcontents number of lines
and then write
lineNo :: String -> IO Int
lineNo fname = do fcontents <- readFile fname
return (lineNo' fcontents)
In this way you have separated the computation and the IO stuff. That is
usually a good idea.
/Lars L