1

I was wondering how to check whether a string is a pangram, as a beginner's exercise. I have two solutions, but I don't understand them at all.

Version 1

import Data.Char (toLower)

isPangram :: String -> Bool
isPangram str = all (`elem` map toLower str) ['a'..'z']

Version 2

import Data.Char (toLower)

isPangram :: String -> Bool
isPangram str = allPresent (map toLower str) ['a'..'z']

allPresent :: String -> String -> Bool
allPresent _ [] = True
allPresent [] _ = False
allPresent (x:xs) ys
    | x `elem` ys = allPresent xs ys
    | otherwise = False

Not sure if they're correct, but any help to simplify or modify this would be appreciated!

1
  • 2
    Well, you will certainly confuse yourself if you try to understand how the second snippet is a pangram checker, because it is not one. Commented Mar 22, 2024 at 16:05

1 Answer 1

1

Your second version is not. That should be:

isPangram :: String -> Bool
isPangram str = allPresent ['a' .. 'z'] (map toLower str)

allPresent :: String -> String -> Bool
allPresent [] _ = True
allPresent _ [] = False
allPresent (x : xs) ys
  | x `elem` ys = allPresent xs ys
  | otherwise = False

Indeed, for a pangram you check if all characters belong to the string. But that is not symmetrical: checking if all elements of X belong to Y is not equivalent to checking if all elements of Y belong to X. We here thus use the first list as the collection of items where we check if each item x of that collection, is an element of the second collection ys.

We thus call allPresent ['a' .. 'z'] (map toLower str) so the first list contains all lowercase characters, the second the lowercase version of the input str. In case the first list is empty, we are done, so we can return True. In case it is not, and the second list is empty, we know it will be False. If both lists are not empty, we check if the first item x of the list is a member of ys, and if so recurse with the rest of the elements xs; otherwise we can return False.

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

4 Comments

Is there any way to implement this without using an external module like Data.char? Also accept a list of characters, and not string? like this isPangram :: [Char] -> Bool
String and [Char] are the same, so it works already with isPangram :: [Char] -> Bool, Data.Char is not an external module, it is part of the base, and thus always "'ships" with the basic library. You could implement toLower yoursel with toLower 'A' = 'a'; toLower 'a' = 'a'; toLower 'B' = 'b', etc.
Could you please add that to the answer above? It's hard for me to understand so I would appreciate any help
Nvm, I figured it out so! Thanks anyway!

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.