I'm working one of the recommended tutorials -- actually, the UPenn online course CS194 -- for learning Haskell, and I have a working solution to the final "challenge exercise" for HW 2. But it seems to be a very brute-force way of doing things, so I'm wondering if this is really the idiomatic Haskell way, or if I'm bringing my imperative programming habits in by accident.
The function is supposed to take a template representing a portion of a Scrabble board, and a set of tiles making up the Scrabble "hand", and see if you can legally play a given word within those constraints. The input would be:
- A Template - a string containing letters or '?' characters, representing empty spaces
- A Hand - a list of characters representing the available letters that can fill in the spaces.
- A Word - the string being checked to see if it fits the template.
A word "fits" the template if:
- Every letter in the template matches the letter at that position in the word
- Every '?' in the template can be replaced by the letter at that position in the word by removing it from the hand
- '?' letters at the end of the template can also be "blank", if the template is longer than the word.
e.g.:
wordFitsTemplate "??r?" [’c’,’x’,’e’,’a’,’b’,’c’,’l’] "care" == True
wordFitsTemplate "??r?" [’c’,’x’,’e’,’w’,’b’,’c’,’l’] "care" == False
wordFitsTemplate "??r?" [’c’,’x’,’e’,’a’,’b’,’c’,’l’] "car" == True
wordFitsTemplate "let" [’x’,’x’] "let" == True
This is what I came up with; I feel like there are too many different patterns and guards that I should be able to condense somehow:
type Hand = [Char]
type Template = String
wordFitsTemplate :: Template -> Hand -> String -> Bool
wordFitsTemplate [] _ [] = True
wordFitsTemplate [] _ _ = False
wordFitsTemplate _ [] _ = False
wordFitsTemplate (t:ts) h []
| t == '?' = wordFitsTemplate ts h []
| otherwise = False
wordFitsTemplate ('?':ts) hs (s:ss)
| s `elem` hs = wordFitsTemplate ts (delete s hs) ss
| otherwise = False
wordFitsTemplate (t:ts) hs (s:ss)
| t == s = wordFitsTemplate ts hs ss
| otherwise = False