Parsing into free monads

Let's say I have the following free monad:

data ExampleF a
  = Foo Int a
  | Bar String (Int -> a)
  deriving Functor

type Example = Free ExampleF  -- this is the free monad want to discuss

I know how I can work with this monad, for example. I could write some good helpers:

foo :: Int -> Example ()
foo i = liftF $ Foo i ()

bar :: String -> Example Int
bar s = liftF $ Bar s id

Therefore, I can write programs in haskell, for example:

fooThenBar :: Example Int
fooThenBar =
  do
    foo 10
    bar "nice"

I know how to print, interpret, etc. But what about parsing it?

Is it possible to write a parser that could parse arbitrary programs such as:

foo 12
bar nice
foo 11
foo 42

Therefore, I can store them, serialize them, use them in cli programs, etc.

The problem I am facing is that the type of program depends on which program is being analyzed. If the program ends with foo type Example (), if it ends with a bartype character Example Int.

( , , , Baz Int (String -> a), Doo (Int -> a), Moz Int a, Foz String a,.... ).

, ?

Boilerplate

, :

{-# LANGUAGE DeriveFunctor #-}

import Control.Monad.Free
import Text.ParserCombinators.Parsec

. gist, .

+4
2

, Example Haskell. , return putStrLn Example (String -> IO ()), , Example .

, , foo bar, >> ( ) *. Backus-Naur :

<program> ::= "" | <expr> "\n" <program>
<expr> ::= "foo " <integer> | "bar " <string>

...

type Parser = Parsec String ()

int :: Parser Int
int = fmap read (many1 digit)

parseFoo :: Parser (Example ())
parseFoo = string "foo " *> fmap foo int

parseBar :: Parser (Example Int)
parseBar = string "bar " *> fmap bar (many1 alphaNum)

... ?

parseExpr :: Parser (Example ???)
parseExpr = parseFoo <|> parseBar

parseFoo parseBar , <|> :: Alternative f => f a -> f a -> f a. , , , : , . ", ", ; Haskell , , , .


, <|> . Example, . †

data Ex a = forall i. Wrap (a i)

parseExpr :: Parser (Ex Example)
parseExpr = fmap Wrap parseFoo <|> fmap Wrap parseBar

typechecks, Example, . , , , - Example: (), Int, parseFoo parseBar. - , Example GADT, , , , a Int ().

data Ty a where
    IntTy :: Ty Int
    UnitTy :: Ty ()

data (a :*: b) i = a i :&: b i

type Sig a b = Ex (a :*: b)
pattern Sig x y = Wrap (x :&: y)

parseExpr :: Parser (Sig Ty Example)
parseExpr = fmap (\x -> Sig UnitTy x) parseFoo <|>
            fmap (\x -> Sig IntTy x) parseBar

Ty (- ) "singleton" , Example. IntTy, , a ~ Int; UnitTy, , a ~ (). ( , , .) :*:, functor product, , ; , Ty Example.

Sig - - . : , , , .

, Sig Either (Example Int) (Example ()) - - - , - , re (, , ) .

. , .

parseProgram :: Parser (Sig Ty Example)
parseProgram = fmap (foldr1 combine) $ parseExpr `sepBy1` (char '\n')
    where combine (Sig _ val) (Sig ty acc) = Sig ty (val >> acc)

, , . . , - , , , . , , .

* , ?

Ex :*: ,

+2

, , , - , . , 100%, - , id () , , Int -> x - , Pure :: Int -> Free ExampleF Int const (something :: Free ExampleF Int).

F , F. , , Free Identity , , , , , :

data MonoidalFree m x = MF m x deriving (Functor)
instance Monoid m => Monad (MonoidalFree m) where
    return x = MF mempty x
    MF m x >>= my_x = case my_x x of MF n y -> MF (mappend m n) y

Free Identity MonoidalFree (Sum Integer), , MF (Sum 3) "Hello" Free . Identity . Free . Identity . Free . Identity $ Pure "Hello" . , data E x = L x | R x deriving (Functor), "" Ls Rs, , Free E MonoidalFree [Bool].

, , , Free Integer -> x, , , , , , , , id. , Free (Bar "string" Pure), Free (Bar "string" (const subExpression)),, , , MonoidalFree [Either Int String].

( , : , ? , ?)

. , , ( , () Int , . - Example (Either () Int), (), fmap Left , Int, fmap Right .

, TCP/IP, , , , , - , , Int -> x .

+2

Source: https://habr.com/ru/post/1623070/


All Articles