3

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.

arrowd
  • 33,231
  • 8
  • 79
  • 110
Olenka
  • 259
  • 3
  • 12
  • well the `do` block is in the list-monad and the return is `return c = [c]` - you will never get any updated `s` here at all - I guess you tried to somehow use a state-monad? – Random Dev Apr 10 '16 at 10:39
  • I guess `| otherwise = check (update s c) (next c)` should do the trick (don't see your `next` nor your `update` so I have no clue if this really fixes your problem) – Random Dev Apr 10 '16 at 10:41
  • @Carsten I've updated my question, so that it is more clear (I hope). Your idea will not work for me, as I need to return value from check and use it into completely different function, together with updated list. I've also tied ">>". And no, I didn't try state-monad, as I'm not that familiar with that one. Can you please give me any tip how to apply it to this situation? – Olenka Apr 10 '16 at 10:53
  • of course `>>` won't work - it's the same! - look just rid yourself of the imperative thinking and don#t try to do this using monads/`do` notation - also have you treally tried it? because it seems to be doing what you described – Random Dev Apr 10 '16 at 11:13
  • Are you sure it's not `check :: [String] -> Char -> [String]` what you actually want? It's hard to guess what is the aim here. Maybe you could add some examples of inputs and expected output. – chi Apr 10 '16 at 11:40

1 Answers1

1

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.

lehins
  • 9,642
  • 2
  • 35
  • 49