Reputation: 57
Need to make a program that checks if a given string is a palindrome, it should work whether the case is different, and should ignore non-alphanumeric characters, only using the ord and chr functions in Data.char and regular functions, nothing else. I was able to create the regular palindrome checker:
reverseStr::String->String
reverStr s | s == [] = []
reverseStr (h:t) = reverseStr t ++ [h]
isPalindrome :: String -> Bool
isPalindrome s = s == reverseStr s
I've started work on a function to normalize case:
normalizeCase::String->String
normalizeCase h | h == [] = []
normalizeCase (h) = if ord h > 64 && ord h < 123
then map (chr $ (ord h + 32)) [h]
else h
But I get these errors:
• Couldn't match expected type ‘Char -> Char’
with actual type ‘Char’
• In the first argument of ‘map’, namely ‘(chr $ (ord h + 32))’
In the expression: map (chr $ (ord h + 32)) [h]
In the expression:
if ord h > 64 && ord h < 123 then
map (chr $ (ord h + 32)) [h]
else
h
|
6 | then map (chr $ (ord h + 32)) [h] | ^^^^^^^^^^^^^^^^^^
• Couldn't match type ‘Char’ with ‘[Char]’
Expected type: String
Actual type: Char
• In the expression: h
In the expression:
if ord h > 64 && ord h < 123 then
map (chr $ (ord h + 32)) [h]
else
h
In an equation for ‘normalizeCase’:
normalizeCase [h]
= if ord h > 64 && ord h < 123 then
map (chr $ (ord h + 32)) [h]
else
h
|
7 | else h | ^
I'm still very new to Haskell and have no idea how to implement ord or chr properly so that it works with this checker, so any help would be appreciated!
Upvotes: 3
Views: 552
Reputation: 54999
In this code:
normalizeCase::String->String
normalizeCase h | h == [] = []
normalizeCase (h) = if ord h > 64 && ord h < 123
then map (chr $ (ord h + 32)) [h]
else h
Your second pattern (h)
(equivalent to just h
) matches any list (as long as it wasn’t already matched by the first pattern, h | h == []
); so h
is a list here and ord h
doesn’t make sense, since ord
expects a Char
, not a [Char]
.
Assuming h
was a character, then chr $ ord h + 32
would also be a character, but map
expects a function as its first argument; this is the source of the error that Char -> Char
was expected but you gave Char
. For the second argument to map
, you pass [h]
, which is a list of a single element h
(which in your code is also a list, so you are providing [[Char]]
when you want [Char]
).
Also assuming h
was a character, your condition ord h > 64 && ord h < 123
matches any character between uppercase A
and lowercase z
, including a few characters you don’t want ([]^_`
). The fact that h
is a list of characters is the source of the error that Char
was expected but you gave [Char]
.
You also seem to be mixing recursive style with map
—in this case you should either use map
or define the function by cases.
Here’s how your code could look with these errors fixed. First, using recursion:
normalizeCase :: String -> String
-- Given an empty list, return an empty list.
-- This happens if the original input was empty,
-- or when we reach the end of the recursion.
normalizeCase [] = []
-- Given a non-empty list,
-- test the first character ‘c’.
normalizeCase (c : cs) = if c >= 'A' && c <= 'Z'
-- If it’s uppercase, lowercase it and
-- prepend it to the result of normalizing
-- the remainder of the string ‘cs’.
then chr (ord c + 32) : normalizeCase cs
-- Otherwise, don’t change it, but still
-- prepend it to the result of normalizing
-- the remainder of the string ‘cs’.
else c : normalizeCase cs
Or, using map
:
normalizeCase :: String -> String
-- Given any string:
normalizeCase s
-- For each character:
= map
-- If it’s uppercase, lowercase it.
(\ c -> if c >= 'A' && c <= 'Z'
then chr (ord c + 32)
else c)
-- Over the whole string.
s
Char
can be compared directly (c >= 'A'
), which is more readable, but if you’re expected to use ord
for the comparison as well, that would be ord c >= 65
.
I know you’re not supposed to use any other standard functions for this task, but for future reference, this can also be implemented very straightforwardly using toLower
from Data.Char
:
import Data.Char (toLower)
normalizeCase :: String -> String
normalizeCase s = map toLower s
-- Alternatively, a point-free/eta-reduced version:
normalizeCase = map toLower
For the additional task of removing non-alphanumeric characters, you can use filter
, a list comprehension with a guard condition, or write a direct recursive version yourself.
Upvotes: 3