Haskell type error message

haskell, typeerror, types

Solution

Looking at this code:

tadd todo = do
    td <- getLine
    td:todo

The problem is that you have `td:todo` as a line by itself; you're using `getLine`, so the whole block should be using `IO`, but your last line is a list. This is what the "can't match" errors are about--the code seems to say that `IO` and `[]` should be the same thing, but of course they aren't.

To lift a value into the monadic context in order to use it as the result value of the `do` block, use the function `return`:

tadd todo = do
    td <- getLine
    return $ td:todo

This will give `tadd` the type `[String] -> IO [String]`. This isn't what you seem to expect the type to be, but from what you've written I don't think you want to be using `[IO String]`.

The same applies to the list comprehension in `tdel` and the final `todo` in `tls`.

Also, your expected type here is off:

mtodo :: [IO String] -> [IO String] -> [IO String]
mtodo "add" todo = tadd todo
mtodo "del" todo = tdel todo
mtodo "ls"  todo = tls todo

The first argument is clearly a `String` here, so based on the above you probably want `mtodo :: String -> [String] -> IO [String]`

This is probably also not what you want:

bege = do
    com <- getLine
    mtodo com []

A few other notes:

Based on the rest of the code you seem to want an interactive program, but this will run it only once. What you probably want instead is something like this:

bege todo = do
    com <- getLine
    todo' <- mtodo com todo
    bege todo'

main = bege []

Your list comprehension `[todo !! x | x <- [0..(length todo-1)], not $ x == rid]` is very inefficient and not idiomatic at all. As a rule of thumb, if you're still learning Haskell you should probably never use `(!!)` unless you're discarding the list afterward. Haskell lists are linear sequences, so indexing requires traversing everything up to that point. Not really the best data structure for what you're doing, but you should at least find some way to do that that doesn't require traversing the list multiple times.

As an example of avoiding `(!!)`, you could rewrite `mapM putStrLn [ (show x) ++ (todo !! x) | x <- [0..(length todo -1)] ]` as `mapM_ putStrLn $ zipWith (\n t -> show n ++ t) [0..] todo`, which avoids all the confusing and superfluous stuff like indexing and worrying about the length of the list, as well as traversing the list only once, instead of traversing it first to compute the length, then partially traversing it up to each item to print it.

This is more a matter of taste, but instead of writing this:

mtodo "add" todo = tadd todo
mtodo "del" todo = tdel todo
mtodo "ls"  todo = tls todo

You could abbreviate it as:

mtodo "add" = tadd
mtodo "del" = tdel
mtodo "ls"  = tls

...which means exactly the same thing, and is arguably clearer by reducing excess noise and making it obvious that all it's doing is selecting one of several other functions based on the string given.

Also, the `let rid = read trem :: Int` bit is unnecessary--just use the function `readLn` instead of `getLine`, which does exactly what you want here. Also, the type annotation is probably unnecessary (and distracting) because the type should be inferred based on what you do with the result.

Problem

For the past couple of days I've been trying to learn Haskell. While I'm slowly getting better but I'm finding it hard to reason with Haskell's IO, probably due to my lack of knowledge. I've been trying to write a simple todo list program. Here's what I've got: ``` tadd todo = do td <- getLine td:todo tdel todo = do trem <- getLine let rid = read trem :: Int [todo !! x | x <- [0..(length todo-1)], not $ x == rid] tls todo = do mapM putStrLn [ (show x) ++ (todo !! x) | x <- [0..(length todo -1)] ] todo mtodo "add" todo = tadd todo mtodo "del" todo = tdel todo mtodo "ls" todo = tls todo bege = do com <- getLine mtodo com [] main = bege ``` I was excepting the mtodo to be `mtodo :: [IO String] -> [IO String] -> [IO String]` and tadd, tdel, tls to be `:: [IO String] -> [IO String]`. Instead I just get this scary error messsage ``` [1 of 1] Compiling Main ( todo.hs, todo.o ) todo.hs:3:9: Couldn't match type `[]' with `IO' Expected type: IO String Actual type: [String] In a stmt of a 'do' block: td : todo In the expression: do { td <- getLine; td : todo } In an equation for `tadd': tadd todo = do { td <- getLine; td : todo } todo.hs:8:9: Couldn't match expected type `IO' with actual type `[]' In a stmt of a 'do' block: [todo !! x | x <- [0 .. (length todo - 1)], not $ x == rid] In the expression: do { trem <- getLine; let rid = ...; [todo !! x | x <- [0 .. (length todo - 1)], not $ x == rid] } In an equation for `tdel': tdel todo = do { trem <- getLine; let rid = ...; [todo !! x | x <- [0 .. (length todo - 1)], not $ x == rid] } todo.hs:12:9: Couldn't match type `[]' with `IO' Expected type: IO [Char] Actual type: [[Char]] In a stmt of a 'do' block: todo In the expression: do { mapM putStrLn [(show x) ++ (todo !! x) | x <- [0 .. (length todo - 1)]]; todo } In an equation for `tls': tls todo = do { mapM putStrLn [(show x) ++ (todo !! x) | x <- [0 .. (length todo - 1)]]; todo } ``` Any ideas what's wrong with my types? (Also - is there anything I should change?). Thanks

Original source