2

I'm currently working on a board evaluator in haskell. I'm trying to use map with a function with multiple parameters; I've read other SO questions regarding this but keep getting type errors so perhaps I'm just misunderstanding the Haskell types (I'm a Python programmer). Either way, here's the code:

scorePiecesRow [] _ = 0
scorePiecesRow (x:xs) y
    | x == y            = 1 + (scorePiecesRow xs y)
    | x == '-'          = 0 + (scorePiecesRow xs y)
    | otherwise         = -1 + (scorePiecesRow xs y)

scorePieces [] _ = 0
scorePieces board y =  foldr (+) 0 (map (scorePiecesRow y) board)

scorePiecesRow works just fine when I pass it anything like "wwwb--" 'w' (which returns 3), but as soon as I call scorePieces (e.g. scorePieces ["www", "bb-"] 'w' which should return 1), I get a bunch of type errors:

<interactive>:37:14:
    Couldn't match expected type `Char' with actual type `[Char]'
    In the expression: "www"
    In the first argument of `scorePieces', namely `["www", "bb-"]'
    In the expression: scorePieces ["www", "bb-"] 'w'

<interactive>:37:21:
    Couldn't match expected type `Char' with actual type `[Char]'
    In the expression: "bb-"
    In the first argument of `scorePieces', namely `["www", "bb-"]'
    In the expression: scorePieces ["www", "bb-"] 'w'

<interactive>:37:28:
    Couldn't match expected type `[Char]' with actual type `Char'
    In the second argument of `scorePieces', namely 'w'
    In the expression: scorePieces ["www", "bb-"] 'w'
    In an equation for `it': it = scorePieces ["www", "bb-"] 'w'

I'm a bit confused by the error messages. The first one tells me, for example, that it's expecting Char, but the first argument of scorePiecesRow takes [Char]. If anyone could shed some light on this, it would be greatly appreciated!

2 Answers 2

4

While Haskell will infer types for you, they're usually very valuable to write out as well to both document your code (in a machine checked fashion!) and check your assumptions. We can do the work of Haskell's type inference engine here to figure out what we know about these functions.

Since scorePiecesRow is added to a number in 1 + (scorePiecesRow xs y) we know the result must be in the typeclass Num (where (+) is defined)

scorePiecesRow :: Num a => ... -> a

Furthermore, by looking at the pattern matching in the arguments we can easily see that the first argument must be a list.

scorePiecesRow :: Num a => [b] -> ... -> a

and since we compare the elements of the first argument with the second argument using (==) we know they must be the same type and in the typeclass Eq (where (==) is defined!).

scorePiecesRow :: (Num a, Eq b) => [b] -> b -> a

Finally, the elements of the first argument are compared with equality to '-', so we know they actually must be Char. Since String is a synonym for [Char] we can impute that.

scorePiecesRow :: (Num a) => String -> Char -> a

We can do the same with scorePieces to learn that

scorePieces :: Num a => String -> String -> a

and this is where we see the problem. You're calling scorePieces ["www", "bb-"] 'w', i.e. with a [String] and a Char while scorePieces expects a String and another String.

The error is telling you exactly this, but it's a little confusing since String and [Char] are the same and GHC tends to reduce types to their simplest form when reporting errors.

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

1 Comment

Ah... that makes a lot of sense! Thanks for taking the time to step through it so thoroughly- this pattern matching thing will get awhile to get used to :)
1

Because scorePiecesRow takes as its arguments a [Char] and a Char, when, in your map function, you call scorePiecesRow y, Haskell decides that y must be of type [Char], as it is given as the first argument to scorePiecesRow.

This is the source of the third error message, as Haskell is expecting a [Char], but you give it a Char.

The first two are essentially the same thing, in that scorePiecesRow y expects a Char, and so, when you map this function over board, Haskell expects board to have type [Char], and it thus fails when you give it a board of type [[Char]].

Perhaps try the following:

scorePiecesRow _ [] = 0
scorePiecesRow y (x:xs)
    | x == y            = 1 + (scorePiecesRow y xs)
    | x == '-'          = 0 + (scorePiecesRow y xs)
    | otherwise         = -1 + (scorePiecesRow y xs)

scorePieces [] _ = 0
scorePieces board y = foldr (+) 0 (map (scorePiecesRow y) board)

or, if you want to keep your scorePiecesRow function the same,

scorePieces [] _ = 0
scorePieces board y = foldr (+) 0 (map (\row -> scorePiecesRow row y) board)

Comments

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.