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
.
if <thing> then True else False
is the same as just<thing>
itself – luqui