main = putStrLn "Hello, World!" {-# OPTIONS_GHC -Wno-missing-export-lists #-} -- | Implementation of a parser-combinator. module Parser where import Control.Applicative import Data.Char ( isAlpha, isDigit, isLower, isSpace, isUpper, ) import Instances -- | ------------------------------------------------- -- | --------------- Core parsers -------------------- -- | ------------------------------------------------- -- | Return a parser that always fails with the given error. -- -- >>> isErrorResult (parse (failed UnexpectedEof) "abc") -- True failed :: ParseError -> Parser a failed = Parser . const . Error -- | Produces a parser that always fails with 'UnexpectedChar' using the given -- character. unexpectedCharParser :: Char -> Parser a unexpectedCharParser = Parser . const . Error . UnexpectedChar -- | Return a parser that succeeds with a character off the input or fails with -- an error if the input is empty. -- -- >>> parse char "abc" -- Result >bc< 'a' -- -- >>> isErrorResult (parse char "") -- True char :: Parser Char char = Parser f where f "" = Error UnexpectedEof f (x : xs) = Result xs x -- | Parse numbers as int until non-digit ---- >>> parse int "abc" -- Result >bc< 'a' -- -- >>> isErrorResult (parse int "") -- True -- -- >>> isErrorResult (parse int "a") -- True int :: Parser Int int = Parser f where -- This is okay because the case statement is small f "" = Error UnexpectedEof f x = case readInt x of Just (v, rest) -> Result rest v Nothing -> Error $ UnexpectedChar (head x) -- | Write a parser that asserts that there is no remaining input. -- -- >>> parse eof "" -- Result >< () -- -- >>> isErrorResult (parse eof "abc") -- True eof :: Parser () eof = Parser f where f "" = Result "" () f x = Error $ ExpectedEof x -- | ------------------------------------------------- -- | --------------- Satisfy parsers ----------------- -- | ------------------------------------------------- -- | All of these parsers use the `satisfy` parser! -- | Return a parser that produces a character but fails if: -- -- * the input is empty; or -- -- * the character does not satisfy the given predicate. -- -- >>> parse (satisfy isUpper) "Abc" -- Result >bc< 'A' -- -- >>> isErrorResult (parse (satisfy isUpper) "abc") -- True satisfy :: (Char -> Bool) -> Parser Char satisfy f = char >>= f' where -- This is okay because guards are small f' c | f c = pure c | otherwise = unexpectedCharParser c -- | Return a parser that produces the given character but fails if: -- -- * the input is empty; or -- -- * the produced character is not equal to the given character. -- -- >>> parse (is 'c') "c" -- Result >< 'c' -- -- >>> isErrorResult (parse (is 'c') "") -- True -- -- >>> isErrorResult (parse (is 'c') "b") -- True is :: Char -> Parser Char is = satisfy . (==) -- | Return a parser that produces any character but fails if: -- -- * the input is empty; or -- -- * the produced character is equal to the given character. -- -- >>> parse (isNot 'c') "b" -- Result >< 'b' -- -- >>> isErrorResult (parse (isNot 'c') "") -- True -- -- >>> isErrorResult (parse (isNot 'c') "c") -- True isNot :: Char -> Parser Char isNot = satisfy . (/=) -- | Write a function that parses one of the characters in the given string. -- -- /Hint/: What does `elem` do? What are its parameters? -- -- >>> parse (oneof "abc") "bcdef" -- Result >cdef< 'b' -- -- >>> isErrorResult (parse (oneof "abc") "def") -- True oneof :: String -> Parser Char oneof = satisfy . flip elem -- | Write a function that parses any character, but fails if it is in the -- given string. -- -- /Hint/: What does `notElem` do? What are its parameters? -- -- >>> parse (noneof "bcd") "abc" -- Result >bc< 'a' -- -- >>> isErrorResult (parse (noneof "abcd") "abc") -- True noneof :: String -> Parser Char noneof = satisfy . flip notElem -- | Return a parser that produces a character between '0' and '9' but fails if -- -- * the input is empty; or -- -- * the produced character is not a digit. -- -- /Hint/: Use the 'isDigit' function digit :: Parser Char digit = satisfy isDigit -- | Return a parser that produces a space character but fails if -- -- * the input is empty; or -- -- * the produced character is not a space. -- -- /Hint/: Use the 'isSpace' function space :: Parser Char space = satisfy isSpace -- | Return a parser that produces a lower-case character but fails if: -- -- * the input is empty; or -- -- * the produced character is not lower-case. -- -- /Hint/: Use the 'isLower' function lower :: Parser Char lower = satisfy isLower -- | Return a parser that produces an upper-case character but fails if: -- -- * the input is empty; or -- -- * the produced character is not upper-case. -- -- /Hint/: Use the 'isUpper' function upper :: Parser Char upper = satisfy isUpper -- | Return a parser that produces an alpha character but fails if: -- -- * the input is empty; or -- -- * the produced character is not alpha. -- -- /Hint/: Use the 'isAlpha' function alpha :: Parser Char alpha = satisfy isAlpha -- | Write a parser that will parse zero or more spaces. -- -- /Hint/: Remember the `space` parser! -- -- >>> parse spaces " abc" -- Result >abc< " " -- -- >>> parse spaces "abc" -- Result >abc< "" spaces :: Parser String spaces = many space -- | Return a parser that produces one or more space characters (consuming -- until the first non-space) but fails if: -- -- * the input is empty; or -- -- * the first produced character is not a space. -- -- /Hint/: Remember the `space` parser! -- -- >>> parse spaces1 " abc" -- Result >abc< " " -- -- >>> isErrorResult $ parse spaces1 "abc" -- True spaces1 :: Parser String spaces1 = some space -- | Write a function that parses the given string (fails otherwise). -- -- /Hint/: Use 'is' and 'traverse'. -- -- >>> parse (string "abc") "abcdef" -- Result >def< "abc" -- -- >>> isErrorResult (parse (string "abc") "bcdef") -- True string :: String -> Parser String string = traverse is -- | ------------------------------------------------- -- | --------------- Token parsers ------------------- -- | ------------------------------------------------- -- | Write a function that applies the given parser, then parses 0 or more -- spaces, then produces the result of the original parser. -- -- /Hint/: You can use the Monad instance or Applicatives -- -- >>> parse (tok (is 'a')) "a bc" -- Result >bc< 'a' -- -- >>> parse (tok (is 'a')) "abc" -- Result >bc< 'a' tok :: Parser a -> Parser a tok = (<* spaces) -- tok p = do -- r <- p -- spaces -- pure r -- | Write a function that parses the given char followed by 0 or more spaces. -- -- /Hint/: Remember the `is` parser -- -- >>> parse (charTok 'a') "abc" -- Result >bc< 'a' -- -- >>> isErrorResult (parse (charTok 'a') "dabc") -- True charTok :: Char -> Parser Char charTok = tok . is -- | Write a parser that parses a comma ',' followed by 0 or more spaces. -- -- /Hint/: We just implemented `charTok` -- -- >>> parse commaTok ",123" -- Result >123< ',' -- -- >>> isErrorResult( parse commaTok "1,23") -- True commaTok :: Parser Char commaTok = charTok ',' -- | Write a function that parses the given string, followed by 0 or more -- spaces. -- -- /Hint/: Remember the `string` parser -- -- >>> parse (stringTok "abc") "abc " -- Result >< "abc" -- -- >>> isErrorResult (parse (stringTok "abc") "bc ") -- True stringTok :: String -> Parser String stringTok = tok . string
Write, Run & Share Haskell code online using OneCompiler's Haskell online compiler for free. It's one of the robust, feature-rich online compilers for Haskell language, running the latest Haskell version 8.6. Getting started with the OneCompiler's Haskell editor is easy and fast. The editor shows sample boilerplate code when you choose language as Haskell and start coding.
OneCompiler's Haskell online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample Haskell program which takes name as input and prints hello message with your name.
main = do
name <- getLine
putStrLn ("Hello " ++ name ++ ", Happy learning!")
Haskell is purely a functional programming language which was introduced in 1990's.
Data-type | Description |
---|---|
Numbers | Haskell is intelligent to identify numbers without specifying data type |
Characters | Haskell is intelligent to identify characters and strings without specifying data type |
Tuple | To declare multiple values in a single data type. Tuples are represented in single paranthesis. For example (10, 20, 'apple') |
Boolean | To represent boolean values, true or false |
List | To declare same type of values in a single data type. Lists are represented in square braces.For example [1, 2, 3] or `['a','b','c','d'] |
When ever you want to perform a set of operations based on a condition or set of conditions, then If-Else/ Nested-If-Else are used.
main = do
let age = 21
if age > 18
then putStrLn "Adult"
else putStrLn "child"
Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increases re-usuability and modularity. Functions play an important role in Haskell, since it is a purely functional language.
multiply :: Integer -> Integer -> Integer --declaration of a function
multiply x1 x2 = x1 * x2 --definition of a function
main = do
putStrLn "Multiplication value is:"
print(multiply 10 5) --calling a function