2
\$\begingroup\$

As a beginner exercise, I made small manual lexer that recognizes three types of inputs:

  • integers: /[-]?[0-9]+/
  • strings, inside double quotes, with backslash escaping
  • nil

using only Data.Char and Data.Maybe.

I would have wanted to do something that looks like this

parse s = tryParseInteger s OR tryParseString s OR tryParseNil 

where each tryParse* would return a (Maybe MyToken) and a failing case (= Nothing) would continue to the next tryParse*. But I didn't find a clean way to do it.

So here it goes:

import Data.Char; import Data.Maybe; data MyToken = MyNil | MyNumber Int | MyString String deriving (Show) tryParse :: String -> Maybe MyToken tryParse "nil" = Just MyNil tryParse (c : t) -- Ignoring white space and parse the tail | isSpace c = tryParse t tryParse s = tryParseNumber s tryParseNumber :: String -> Maybe MyToken tryParseNumber s = case (parseNum s) of Just v -> Just $ MyNumber v Nothing -> tryParseString s tryParseString :: String -> Maybe MyToken tryParseString ('"':t) = fmap MyString (parseInsideString t) tryParseString _ = Nothing parseInsideString :: String -> Maybe String parseInsideString ('\\':'"':cs) = fmap ('"':) (parseInsideString cs) parseInsideString ('"':_) = Just "" parseInsideString (c:cs) = fmap (c:) (parseInsideString cs) parseInsideString _ = Nothing parseNum :: String -> Maybe Int parseNum ('-':xs) = fmap (\x -> -x) (parseNum xs) parseNum cs@(c:_) | isDigit c = foldl step Nothing cs | otherwise = Nothing where step acc c | isDigit c = Just ((10 * fromMaybe 0 acc) + (digitToInt c)) | otherwise = acc main = print $ tryParse "\"abcd\\\"efgh\"" 
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I would have wanted to do something that looks like this

parse s = tryParseInteger s OR tryParseString s OR tryParseNil 

OR is <|>:

tryParse :: String -> Maybe MyToken tryParse = tryParse' . dropWhile isSpace where tryParse' s = MyNumber <$> parseNumber s <|> tryParseString s <|> tryParseNil s tryParseNil :: String -> Maybe MyToken tryParseNil "nil" = Just MyNil tryParseNil _ = Nothing 
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.