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


Reply via email to