Summer
Summer

Reputation: 23

Using the haskell map function with a string

I'm trying to use the map function in haskell

I've got this:

lexi :: String -> [[String]]
lexi x = map (words.lines) x

I want to be able to put a string in to x, so it can be run like this

lexi ("string here")

But get the error

Couldn't match type ‘[Char]’ with ‘Char’
Expected type: String -> String
  Actual type: String -> [String]
In the second argument of ‘(.)’, namely ‘lines’
In the first argument of ‘map’, namely ‘(words . lines)’

Couldn't match type ‘Char’ with ‘[Char]’
Expected type: [String]
  Actual type: String
In the second argument of ‘map’, namely ‘x’
In the expression: map (words . lines) x

I know that if I use

lexi = map (words.lines) 

it works fine when I run lexi ("string here"), but need the variable to use later on

Could some please explain why this doesn't work and how to fix it?

Thank you :)

Upvotes: 0

Views: 3381

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120751

This answer refers to an old version of the question.

So let's get this quite clear (please always add the type signature of all functions you're talking about!)

function :: Char -> [String]

Well, then the type of map function is [Char] -> [[String]], i.e. String -> [[String]]. But you want the result to be only [String], not a triply-nested list. You probably want to join the lists of two levels together; in general the function to use for list-joining purposes is concat (or more generally, join from the Control.Monad module). In this case, you have two different options:

  • Join the result of each call to function. I.e., instead of mapping function alone, you map join . function, which has type Char -> String. Mapping that has the desired type String -> [String].

    lexi = map $ join . function
    
  • Join the final result of the mapping, i.e. lexi = join . map function. This combination of mapping and joining the results is actually an extremely common task, it has a special operator: monadic bind!

    lexi x = x >>= function
    

New version

So we know that

words, lines :: String -> [String]

thus words . lines can not work, because you're trying to feed a list of strings into a function that only accepts a single string. What you can of course do though is map words over the result, i.e. map words . lines. That has in fact the correct signature and probably does just what you want.

Upvotes: 4

Related Questions