Created
July 14, 2020 09:27
-
-
Save paolino/4174e87f6aed20cff0dee8e5883d53f8 to your computer and use it in GitHub Desktop.
parse a list of different types driven by parser type
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
{-# LANGUAGE GADTs #-} | |
{-# LANGUAGE OverloadedStrings #-} | |
{-# LANGUAGE RankNTypes #-} | |
{-# LANGUAGE ScopedTypeVariables #-} | |
{-# LANGUAGE TypeApplications #-} | |
{-# LANGUAGE TypeOperators #-} | |
module Lib.Parse where | |
import Control.Lens (Getting, (^?), _Just) | |
import Data.Aeson (Value) | |
import Data.Typeable (typeOf) | |
import Protolude (First, TypeRep, Typeable, panic) | |
-- | a tuple | |
data a :*: b = a :*: b deriving (Show, Eq) | |
infixr 0 :*: | |
-- | A parser from Value to 'a' | |
type Preview a = Getting (First a) Value a | |
-- | A parser that can handle missing values | |
data Parser a = Parser (Maybe a) (Preview a) | |
infixr 0 :**: | |
-- | tuple like collection of parsers | |
data Q a where | |
-- | cons a lens | |
(:**:) :: (Typeable a, Typeable b) => Parser a -> Q b -> Q (a :*: b) | |
-- | shortcut to avoid L | |
(:***:) :: (Typeable a, Typeable b) => Parser a -> Parser b -> Q (a :*: b) | |
L :: Typeable a => Parser a -> Q a | |
-- | shortcut for a parser that handle missing values | |
required :: Preview a -> Parser a | |
required = Parser Nothing | |
-- | shortcut for parsers that have a default if value is missing | |
optional :: a -> Preview a -> Parser a | |
optional = Parser . Just | |
-- | as 'L' | |
only :: Typeable a => Parser a -> Q a | |
only = L | |
-- | what wrong can happen | |
data ParseGIssue | |
= ParseGIssue (Int, Maybe Value, TypeRep) | |
| ParseGWrongNumberOfValues | |
deriving (Eq, Show) | |
-- internal parsing | |
parseG :: Q a -> [(Int, Maybe Value)] -> Either ParseGIssue a | |
parseG (L l) [v] = parseOne l v | |
parseG (l :**: ls) (v : vs) = (:*:) <$> parseOne l v <*> parseG ls vs | |
parseG (l :***: h) [v, w] = (:*:) <$> parseOne l v <*> parseOne h w | |
parseG _ _ = Left ParseGWrongNumberOfValues | |
-- | parse a list of values which can be missing | |
parse :: | |
-- | tuple of parsers | |
Q a -> | |
-- | list of values | |
[Maybe Value] -> | |
-- | problems or tuple of parsed values | |
Either ParseGIssue a | |
parse ts = parseG ts . zip [0 ..] | |
-- apply one parser | |
parseOne :: forall a. Typeable a => Parser a -> (Int, Maybe Value) -> Either ParseGIssue a | |
parseOne (Parser m l) (n, v) = case v ^? _Just . l of | |
Nothing -> case m of | |
Nothing -> Left $ ParseGIssue (n, v, typeOf @a $ panic "no value") | |
Just x -> Right x | |
Just x -> Right x |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.