Palindromes

The first part of this course focused on the Haskell language – but just like learning a foreign language, you can’t become fluent in it without a lot of practice. The best way to become fluent in a foreign language is to speak it a lot, and especially to have conversations. The best way to become fluent in Haskell is to try writing a lot of functions and have conversations with GHCi. This part of the course is going to get you busy doing those things.

Palindromes

We’re going to write a small interactive program, with just a few functions in it, that checks to see if a word that the “user” inputs is a palindrome.

A palindrome is a word that is spelled the same forward and backward, for example, “mom”, or everyone’s favorite: “tacocat”.

We can write a function in Haskell that checks to see if a String is a palindrome. We’re going to call it isPalindrome. It will test a String and give us a yes or no answer.

isPalindrome :: String -> Bool

A word is a palindrome if it is the same as the reverse of that word.

isPalindrome :: String -> Bool
isPalindrome word =
    word == reverse word

We’re going to be building on this basic function over the course of this session, so you should write this into your file – the main.hs file or whatever you want to call it. The name of that file isn’t important as long as we make sure that we load it into GHCi.

List reversal

Now, reverseAPI documentation for reverse is a function that is given to us by the Prelude module that we mentioned previously, that standard set of functions and types that gets loaded automatically. Let’s look at the type of that function in the REPL.

To query the type of a function, we can use this :type command.

λ> :type reverse
reverse :: [a] -> [a]

We could also abbreviate that as just :t.

λ> :t reverse
reverse :: [a] -> [a]

We can see that reverse has the type [a] -> [a]. That means that it takes in a list of absolutely anything. It could be a list of integers, list of booleans, or a list of good dogs; this function doesn’t care. And it returns a list of the same type. So if we give it a list of Integer, it will give us back a list of Integer. If we give it a list of dogs, it will give us back a list of dogs.

Strings are lists

We said that we could use this with a String in our isPalindrome function, even though we just saw that it has to take a list.

We can use the :info command in GHCi to look at what a String is.

λ> :info String
type String = [Char]

A String is defined as a type synonym, also called a type alias, for a list of characters.The type keyword is used to declare type synonyms.

This isn’t super important; it’s a way of giving a new name to a specialization of an already-existing type, so instead of having to write [Char], if we prefer, we can write the word String, and they mean exactly the same thing.

Let’s try out this reverse function a few times to make sure we’re comfortable with what it does. We can reverse a list of numbers.

λ> reverse [1, 2, 3, 4]
[4,3,2,1]

We can reverse a list of characters, also known as a string.

λ> reverse "Julie"
"eiluJ"

We can even reverse a list of lists, so here are some very good dogs.

λ> reverse ["Alonzo", "Melman", "Dallas"]
["Dallas","Melman","Alonzo"]

We notice that only the top level gets reversed, so ["Alonzo", "Melman", "Dallas"] reverses to ["Dallas", "Melman", "Alonzo"]. Even though each element of that list is itself a list, the characters within those words don’t get reversed.

Experiment with isPalindrome

Next let’s try out the isPalindrome function that we wrote. It only needs one input string – for example, “mom”, which should be a palindrome.

λ> :load main.hs

λ> isPalindrome "mom"
True

And our program confirms it.

Next we see that “tacocat” is also a palindrome, but “Chris” is, sadly, not a palindrome.

λ> isPalindrome "tacocat"
True

λ> isPalindrome "Chris"
False

So far, so good!

If you like, see if you can come up with inputs to this that we would normally consider palindromes but that this function rejects. For example, consider capitalization, whether we think that a capital letter should be considered the same as a lowercase letter in this; or, the word “tacocat” is really two words, ‘taco’ and ‘cat’ – try putting a space in between them as the input to this function and see what it does.

Join Type Classes for courses and projects to get you started and make you an expert in FP with Haskell.