Last active
July 7, 2020 13:48
-
-
Save ObjectBoxPC/7dbdfedc2482d364a41445e5322e54ff to your computer and use it in GitHub Desktop.
Simple Haskell program to check if the input (command-line arguments) form a pangram, containing all 26 letters of the English alphabet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Data.Char (toUpper) | |
import Data.List (intercalate) | |
import Data.List.NonEmpty (NonEmpty, nonEmpty, toList) | |
import System.Environment (getArgs) | |
data PangramResult = Pangram | MissingLetters (NonEmpty Char) | |
checkPangram :: String -> PangramResult | |
checkPangram s = case nonEmpty missingLetters of | |
Just ls -> MissingLetters ls | |
Nothing -> Pangram | |
where | |
missingLetters = filter (not . (`elem` normalized)) ['A'..'Z'] | |
normalized = map toUpper s | |
getText :: IO String | |
getText = concat <$> getArgs | |
showLetters :: NonEmpty Char -> String | |
showLetters = intercalate ", " . map (:[]) . toList | |
main = do | |
text <- getText | |
let | |
message = case checkPangram text of | |
Pangram -> "Pangram" | |
MissingLetters ls -> "Not a pangram: Missing " ++ showLetters ls | |
putStrLn message |
@ObjectBoxPC I'm glad it was helpful. I definitely relate to the tendency to want to write your main
as a pipeline, so I tend to favor the putStrLn . msg . concat =<< getArgs
style. It never bothered me that the entrance to the pipeline is on the right side, because that's how function application is written in every programming language and traditionally on paper.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@friedbrice Thanks a lot for your detailed comments. I've made changes based on your suggestions.
Some specific responses:
allElems
/subset
, but I suppose I went a bit overboard in trying to make it point-free. I wasn't used to using functions as infix operators so I had(flip elem)
instead of(`elem` xs)
However, thinking ofelem
andsubset
as set symbols does make the infix version more intuitive to me.main
was meant to convey a sort of pipeline like in a Unix shell. But do-notation version does make it shorter so I went for that.