0
votes

I'm receiving errors while writing a function that takes a string from the user and decides returns bool whether it's a pangram or not. I'm having complications due to this error

"Couldn't match expected type Char with actual type [Char]".

This is all the code I have in a .hs file.

lowerlist = ['a'..'z']
upperlist = ['A'.. 'Z']
tlist = zip upperlist lowerlist

pangram s = [if xs == lowerlist then True else False| xs <- lowerlist, xs `elem` s]

If I put [] around xs then it just gives me a bunch of "[True, false, true, true, .....]".

Can someone help solve this problem for me and perhaps give me tips on this program?

1
Can you explain the supposed logic of your solution in plain English?Fyodor Soikin
@FyodorSoikin s is the string taken from user and xs is generated by matching letters in "lowerlist" and s, and then if xs has the same letters as "lowerlist" then returns True for pangram.ChadT
Nitpick: if <thing> then True else False is the same as just <thing> itselfluqui

1 Answers

1
votes

First, the answer to the literal question you asked. The way to refer to a list itself within the list comprehension is to give it a binding. Contrived examples:

a2z = 'a':[ succ (a2z!!i) | i <- [0..24]]
fibo = 0:1:[fibo !! i + fibo !! (i+1) | i <- [0..]]

Now, as for the pangram program. It looks as if you want hints to solve it yourself, not a complete solution, so: what you want is not to compare your string to the literal alphabet, but to test whether a predicate based on the input string is true of every character in the alphabet. That is, your predicate is some function of the input which must be true of all characters in the alphabet. You might try filling in the hole in this skeleton:

import Data.Char (toLower)

main :: IO ()
main = interact ( unlines . map show . map isPangram . lines )

isPangram :: String -> Bool
isPangram xs = all (_ ys) alphabet
  where alphabet = ['a'..'z']
        ys = map toLower xs

As GHC will tell you, the type of the missing function is :: String -> Char -> Bool. So you might also write it this way:

import Data.Char (toLower)

main :: IO ()
main = interact ( unlines . map show . map isPangram . lines )

isPangram :: String -> Bool
isPangram xs = all p alphabet
  where alphabet = ['a'..'z']
        ys = map toLower xs

        p :: Char -> Bool
        p c = _

You can remove the ys parameter and simply refer to ys directly within p, as that variable, holding the normalized input, is in the scope of p.

Maybe you want a tweak to your current program. In this case, the list you’re generating is a list of Bool. You can get the program to work if the list contains, for each letter of the alphabet, True if that letter appears in the input, False if not. You can also use all to reduce this list to a single Boolean value.

If you instead want to accumulate a set of all the letters that have been encountered so far in the string, and stop when it equals the entire alphabet, you want a more complex recursive tail-recursive function. It would build its accumulating parameter as something like insertion into a Data.List.Ordered, make sure to insert only elements from the alphabet, each only once, and stop when the cardinality of the accumulated set (which is the length of the ordered list) is the same as that of the alphabet. It would, however, be more efficient to start with the complete alphabet and remove elements as they are encountered, stopping when either the input or the alphabet are empty:

import Data.Char (toLower)
import Data.List -- You’ll need a function from here.

main :: IO ()
main = interact ( unlines . map show . map isPangram . lines )

isPangram :: String -> Bool
isPangram xs = isPangram' alphabet ys
  where alphabet = ['a'..'z']
        ys = map toLower xs

        isPangram' :: [Char] -> [Char] -> Bool
        isPangram' [] _ = _  -- There are no more letters to search for.
        isPangram' _ [] = _ -- There is nothing left to search.
        isPangram' ws (z:zs) = isPangram' _ _ -- Remove an element from both lists.

An alternative approach would be to normalize the input, filter out all extraneous elements, and take the nub of what’s left as a list of Char.