[Haskell-beginners] Convert String to List/Array of Numbers

Tim Perry perry2of5 at yahoo.com
Wed Sep 8 14:06:10 EDT 2010


You either need to write:

convert x = (map (map read . words) . lines) x

or you need to write:

convert x = map (map read . words) $ lines x


The original function was written as
convert = map (map read . words) . lines

The original is in what is called "point free" form. Values are called "points" 
so you have left out the value making the function "point free".  I think this 
is one of the most annoying "features" of Haskell because you can't glance at a 
function and know how many parameters it takes unless you also know how many 
parameters each of the functions it uses need. But that aside, it is very 
common. Real World Haskell covers it in Chapter 5.
http://book.realworldhaskell.org/read/writing-a-library-working-with-json-data.html


Good luck,
Tim




----- Original Message ----
From: Lorenzo Isella <lorenzo.isella at gmail.com>
To: Daniel Fischer <daniel.is.fischer at web.de>
Cc: beginners at haskell.org
Sent: Wed, September 8, 2010 10:24:12 AM
Subject: Re: [Haskell-beginners] Convert String to List/Array of Numbers

Hi Daniel,
Thanks for your help.
I have a couple of questions left
(1) The first one is quite down to earth.
The snippet below

---------------------------------------------------
main :: IO ()

main = do
   txt <- readFile "mydata.dat"

   let dat = convert txt

   print dat -- this prints out my chunk of data

   return ()

convert x = lines x

-----------------------------------------------

pretty much does what it is supposed to do, but if I use this definition 
of convert x

convert x = map (map read . words) . lines x

I bump into compilation errors. Is that the way I am supposed to deal 
with your function?

(2) This is a bit more about I/O in general. I start an action with "do" 
to read some files and I define outside the action some functions which 
are supposed to operate (within the do action) on the read data.
Is this the way it always has to be? I read something about monads but 
did not get very far (and hope that they are not badly needed for simple 
I/O). Is there a way in Haskell to have the action return to the outside 
world e.g. the value of dat and then work with it elsewhere?
That is what I would do in Python or R, but I think I understood that 
Haskell's philosophy is different...
Am I on the right track here? And what is the benefit of this?

Cheers

Lorenzo


On 09/08/2010 04:06 PM, Daniel Fischer wrote:
> On Wednesday 08 September 2010 15:31:19, Lorenzo Isella wrote:
>> Dear All,
>> I must be stuck on something pretty basic (I am struggling badly with
>> I/O). Let us assume you have a rather simple file mydata.dat (3 columns
>> of integer numbers), see below.
>>
>>
>>
>> 1246191122 1336 1337
>> 1246191142 1336 1337
>> 1246191162 1336 1337
>> 1246191182 1336 1337
>> 1246191202 1336 1337
>> 1246191222 1336 1337
>> 1246191242 1336 1337
>> 1246191262 1336 1337
>> 1246191282 1336 1337
>> 1246191302 1336 1337
>> 1246191322 1336 1337
>> 1246191342 1336 1337
>> 1246191362 1336 1337
>> 1246191382 1336 1337
>> 1246191402 1336 1337
>> 1246191422 1336 1337
>>
>> Now, my intended pipeline could be
>>
>> read file as string-->  convert to list of integers-->pass it to hmatrix
>> (or try to convert it into a matrix/array).
>> Leaving aside the last step, I can easily do something like
>>
>> let dat=readFile "mydata.dat"
>>
>>
>> in the interactive shell and get a string,
>
> Not quite. `dat' is the IO-action that reads the file, of type (IO String)
> and not a String.
> In a programme, you'd do something like
>
> main = do
>      ... -- argument parsing perhaps
>      txt<- readFile "mydata.dat"
>      let dat = convert txt
>      doSomething with dat
>
>> but I am having problems in
>> converting this to a list or anything more manageable (where every entry
>> is an integer number i.e. something which can be summed, subtracted
>> etc...). Ideally even a list where every entry is a row (a list in
>> itself) would do.
>
> Depending on what the reult type should be, different solutions are
> required.
> The simplest solutions for such a file format are built from
>
> read  -- to convert e.g. "135" to 135
> lines :: String ->  [String]
> words :: String ->  [String]
> map :: (a ->  b) ->  [a] ->  [b]
>
> If you want a flat list of Integers from that file,
>
> convert = map read . words
>
> will do. First, `words' splits the String on whitespace (spaces and
> newlines), producing a list of digit-strings, those are then read as
> Integers.
>
> If you want a list of lists, each line its own list inside the top level
> list,
>
> convert = map (map read . words) . lines
>
> is what you want.
>
> If you want to convert each line into a different data structure, say
> (Integer, Double, Int64), the general form would still be
>
> convert = map parseLine . lines
>
> and parseLine would depend on the structure you want. For the above,
>
> parseLine str
>      = case words str of
>          (a : b : c : _) ->  (read a, read b, read c)
>          _ ->  error "Bad line format"
>
> would be a solution.
>
> For any but the simplest formats, you should write a real parser to deal
> with possible bad formatting though (writing parsers is fun in Haskell).
>
>> I found online this suggestion
>> http://bit.ly/9jv1WG
>> but I am not sure if it really applies to this case.
>> Many thanks
>>
>> Lorenzo
>

_______________________________________________
Beginners mailing list
Beginners at haskell.org
http://www.haskell.org/mailman/listinfo/beginners



More information about the Beginners mailing list