5
votes

I am having trouble with how to use isUpper, isLower, and isDigit. Specifically I am trying to take a string and return a list of tuples for each character in the string containing three Bool values for if the character is an uppercase letter, a lowercase letter, or a digit. So the string "Ab2" would return the list [(True, False, False), (False, True, False), (False, False, True)]. This is what I have:

import Data.Char
uppercaseList :: [a] -> [(Bool, Bool, Bool)]
uppercaseList xs = [(isUpper, isLower, isDigit)]

I think I need to pass the character of the string into isUpper, isLower, and isDigit, but I don't see how to. I'm sorry if this is a dumb question, but nothing I've found addresses my confusion so far.

2
Do you know about list comprehension? Or the function map and lambdas \x -> (isUpper x, isLower x, isDigit x)?epsilonhalbe
Btw you should change the first part of your type signature to [Char] or String. [a] represents a list of arbitrary elements.epsilonhalbe

2 Answers

8
votes

You need to do check on each element of the list (xs). Usually this kind of task is done by using map

import Data.Char
uppercaseList :: String -> [(Bool, Bool, Bool)]
uppercaseList xs = map (\x -> (isUpper x, isLower x, isDigit x)) xs

or list comprehension

uppercaseList xs = [ (isUpper x, isLower x, isDigit x) | x <- xs ]

or write from scratch

uppercaseList [] = []
uppercaseList (x:xs) = (isUpper x, isLower x, isDigit x) : uppercaseList xs
2
votes

The problem with your approach:

uppercaseList xs = [(isUpper, isLower, isDigit)]

is that it does not take the list xs into account at all: it is not mentioned in the body. So that means xs has no impact on the output.

What you have done ihere is constructing a list as output with one element: a tuple that contains three functions (yes these are functions, not Bools).

In order to inspect the character, you need to call the functions on an element of the list.

Calling a function on a list is done with map :: (a -> b) -> [a] -> [b]. Map takes as first argument a function f, and as second argument a list of elements (for instance [x1, x2, x3, x4]). It applies the function f on all elements of the input, and generates a list [f x1, f x2, f x3, f x4]). This is done in a lazy manner.

Here we thus need a function f :: Char -> (Bool, Bool, Bool). Based on the specifications, the function looks like:

import Data.Char(isUpper, isLower, isDigit)

f :: Char -> (Bool, Bool, Bool)
f x = (isUpper x, isLower x, isDigit x)

We can then write:

uppercaseList :: [Char] -> [(Bool, Bool, Bool)]
uppercaseList = map f

Since it is weird to see a function f (we can of course give it a more semantical name), at the top level of a file. We can decide to scope it (or use a lambda expression instead):

uppercaseList :: [Char] -> [(Bool, Bool, Bool)]
uppercaseList = map f
    where f x = (isUpper x, isLower x, isDigit x)