Search code examples
stringhaskellreturnmonadsguard-statement

returning a value from do statement in a guards haskell


I'm trying to find if some letter is already used in any string in the list of strings. If yes - choose next letter to compare. If no - return this letter and update the initial list.

To check in the list I'm using:

check:: [String] -> Char -> Char
check s c 
    | any (elem c) s = check s (next c)
    | otherwise = do update s c 
                     return c

But it gives me an error:

Couldn't match type ‘[Char]’ with ‘Char’
Expected type: [String] -> [Char] -> Char
Actual type: [String] -> [Char] -> [Char]
In a stmt of a 'do' block: update s c

My update function has following declaration:

update:: [String] -> Char -> [String]

Is there any correct way to perform 2 actions in the guard otherwise? I need to return c in order to use it in another recursive function, which takes as the parameters both Char c and updated [String] s

When I had this functions returning only c, without updating the list, there where no errors:

check:: [String] -> Char -> Char
check s c 
    | any (elem c) s = check s (next c)
    | otherwise = c

Any tips are welcome.

Update: My next function is:

next :: Char -> Char
next 'Z' = 'A'
next c = chr (ord c + 1)

And for update I've tried:

update:: [String] -> Char -> [String]
update s c = s ++ [[c]]

The thing is that later on, I need to use [String] which is the result of update, together with Char c (result from check) into another function. That's why, after performing check, I need to return a value, and to update a list with it.


Solution

  • Haskell is a functional language, hence you cannot (should not) think of mutating a data structure, instead a function should return an updated version of that data structure, and whatever else you need. Most common way to do it is returning a tuple of values you need. Here is what you are probably looking for:

    check:: [String] -> Char -> (Char, [String])
    check s c 
        | any (elem c) s = check s (next c)
        | otherwise = (c, s ++ [[c]])
    

    This way you get "this" letter and updated version of the initial list of Strings.