0

I'm trying to create a function for a board game that will read a position on the board as a string and convert to a coordinate that can be used in the program e.g. "D4 => (3,3), "F2" => (5,1)".

So far I have this:

getCoord :: String -> Maybe(Int, Int)
getCoord s = 
    let alphas = "ABCDEFGH"
        coord1 = head(s)
        coord2 = tail(s)
    in ((elemIndex coord1 alphas)-1, read(head coord2)-1)

I'm still learning about the use of Maybe in Haskell and am encountering the error:

• Couldn't match expected type ‘Maybe (Int, Int)’
              with actual type ‘(Maybe Int, Integer)’
• In the expression:
    ((elemIndex coord1 alphas) - 1, read (head coord2) - 1)

Would appreciate your help on where I might be going wrong. Thanks!

3
  • 1
    In Maybe (Int, Int), the Int tuple is the argument of Maybe. But (Maybe Int, Integer) is a tuple of Maybe Int and another Int. So if the value of the Maybe is Nothing, for the second case you still need to provide the second Int. Commented Apr 17, 2020 at 11:23
  • You'll also want to use pattern matching instead of head and tail. getCoord [coord1, coord2] = .... Shorter and longer strings can be handled separately. Commented Apr 17, 2020 at 11:40
  • 1
    Further, elemIndex returns a Maybe Int, not an Int. You can't directly subtract 1 from that value. Commented Apr 17, 2020 at 11:47

1 Answer 1

2

The problem you're facing is that elemIndex returns a Maybe Int. Since you're also trying to return a Maybe type, the best way to work with this is using a do block to perform operations inside the Maybe monad. This lets you use Maybe values as if they were normal values as long as your output will get wrapped back up in a Maybe. (If you need more information about how monads work, there are plenty of good answers here explaining it, and lots of other great posts across the internet.)

import Text.Read (readMaybe)
import Data.List (elemIndex)

getCoords :: String -> Maybe(Int, Int)
getCoords (coord1:coord2) = do
  let alphas = "ABCDEFGH"
  row <- elemIndex coord1 alphas
  col <- readMaybe coord2
  return (row, col - 1)
getCoords _ = Nothing

Note a couple other differences from your original.

  1. The use of readMaybe instead of read. readMaybe is a special version of read that returns a value of type Maybe a. Since we're already working in a Maybe context, it's better to have a no-parse return Nothing than throw an error.

  2. No - 1 on the row. elemIndex already has the behavior you want, i.e. A will return 0, etc.

  3. Pattern match instead of head and tail. This lets you account for the case where the string is empty.

  4. Extra definition to match empty list and return Nothing. The advantage of using a Maybe type is that you can return a value for errors instead of getting a Runtime error. In order to make use of that, we have to make sure we handle all of the cases.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer! This makes sense to me however I can't seem to get it to compile, i get a parse error on input row
Yikes. I'm missing the do. EDIT: fixed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.