Why is a list of strings suddenly a list of list of strings?

I have a function:

setDisplays :: Char -> [String] -> IO()
setDisplays mode dIds
    | mode == 'l' = chngDispl (head dIds)
    | mode == 'e' = chngDispl (tail dIds)
    where
      chngDispl on = mapM_ (\id -> callProcess "xrandr" ["--output", id, "--auto"]) on

that gets a list of strings with the ids of Displays provided by xrandr which looks like this ["eDP1", "HDMI1"]. The list is passed to setDisplays by binding an IO ():

getDisplays >>= setDisplays 'e'

Now, I get the following error message: parser.hs:50:37:

    Couldn't match type ‘Char’ with ‘[Char]’
    Expected type: [[String]]
      Actual type: [String]
    In the first argument of ‘head’, namely ‘dIds’
    In the first argument of ‘chngDispl’, namely ‘(head dIds)’
Failed, modules loaded: none.

which I don't get. Even ghc-mod is telling me that the name dIds when it is first mentioned identifies [String] and when I typecheck with ghc-mod in the function call it identifies [[[Char]]]. What is happening here?

Upvotes: 1

Views: 96

Answers (2)

WilQu
WilQu

Reputation: 7393

If dIds is a [String], then the result of head will be a String, but chngDispl expects a [String]. That’s why the compiler thinks that the argument of head should be a [[String]].

Wrap head dIds in a list and the error should go away.

You should generally avoid head and use pattern matching instead. You can rewrite your function like this:

setDisplays :: Char -> [String] -> IO()
setDisplays mode (id:ids)
    | mode == 'l' = chngDispl [id]
    | mode == 'e' = chngDispl ids
    where
      chngDispl on = mapM_ (\id -> callProcess "xrandr" ["--output", id, "--auto"]) on

Note that this will fail if the list is empty (but so will head), you should handle that case as well.

Upvotes: 4

Tobi Nary
Tobi Nary

Reputation: 4596

You are using head on dIds and expect that to be a [String]. Thus, type inference tells us, that dIds to be used that way should be of type [[String]].

Also, you are using tail on dIds one line below. That doesn't type match.

Upvotes: 4

Related Questions