Friday, September 07, 2012

Parselets :: safe, single expression parser/pretty-printer serializer/deserializer



I want to express  the parse and pretty-print of a data structure with a single, declarative expression. I also want to make the syntax general enough to adapt to any serialization/deserialization format, binary or textual, and for any string format.

The first is done. I used the idea of Formlets and applied it to parse-print. This is the resulting expression for an  example datatype:

data P = I {getInt :: Int} | S {getString :: String} deriving (Show)

This is the instance of  Parselet for P to parse/print from/to Strings (see the class definition below)  :

instance ParseLet P String where
    parse mpx  =   I <$> (str "I" *> pString (sel getInt mpx ))
              <|>  S <$> (str "S" *> pString (sel getString mpx ))

The single expression produces the text serialization and deserialization:

main =  do
   putStrLn . serial $ S "hi"
   print (deserial "I 2" :: Maybe P )


This is the output:

e>runghc demos\parselets.hs
S {getString="hi"}
Just (I 2)


To do this,I  coded some applicative instance that wraps both a non monadic parser and a non-monadic serializer. I also found a way to express  conditional serialization as an Alternative expression within an Applicative expression (sel), so that it mimic the shape of an applicative parser expression


Because there is a single expression for serialization and deserializartion,  it can be guaranteed  that the first will produce a result that will be read without errors by the second:

This is the complete source of parselets.hs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
{-# LANGUAGE
             ScopedTypeVariables
             ,TypeSynonymInstances
             ,FlexibleInstances
             ,MultiParamTypeClasses

          #-}

import Control.Applicative
import Data.Monoid
import System.IO.Unsafe
import Control.Exception  as CE
import Data.List(isPrefixOf)
import Data.Maybe
import Debug.Trace
(!>)= flip trace

data RS v a= RS v  (Maybe a)

newtype RSView v a=  RSView{runRSView :: (v -> (RS v a,v))}

instance Functor (RSView v) where
  fmap f (RSView p)=RSView $  \v -> let (RS v1 x, r)= p v
                                    in (RS v1 (fmap f x),r)



instance Monoid v => Applicative( RSView v) where
  pure a  = RSView ( \v  -> (RS  mempty $ Just a,v))

  RSView f <*> RSView g= RSView ( \v  ->

                   let (RS v1 k,r)  = f v 

                       (RS v2 x,r2) = g r

                   in  (RS (mappend v1 v2) (k <*> x),r2))

instance  Monoid v => Alternative (RSView v) where

  empty= RSView $ \v -> (RS mempty Nothing, v)
  RSView f <|> RSView g= RSView ( \v  ->

                   let rs@(RS v1 k,r)  = f v 



                   in case k of
                     Just _  -> rs
                     Nothing -> g v )




class Monoid v =>  ParseLet a v where
  parse :: Maybe a -> RSView v a -- must not use pattern match

serial :: ParseLet a v => a -> v
serial x    = getSerial $ (runRSView $ parse  (Just x)) mempty
   where
   getSerial  (RS v _,_)= v

deserial :: ParseLet a v =>  v -> Maybe a
deserial str= getDeserial ( (runRSView ( parse Nothing)) str)
   where
   getDeserial (RS _ x,_)= x

sel f mpx= unsafePerformIO $
   CE.handle (\(e:: SomeException) -> return Nothing)
   $ let x= f $ fromJust mpx in x `seq` return (Just x)




pString :: (Read a, Show a)=>  Maybe a -> RSView String a
pString (Just fpx)= RSView $ \str ->  (RS (show$ fpx) (Just fpx),str)


pString Nothing  = RSView $ \str ->
          case readsPrec  1 str of
                  []      ->  (RS " " Nothing, str)
                  (x,r):_ ->  (RS " " (Just x), r)


--str :: String -> RSView String ()
str s= RSView ( \st ->
   let readit= if isPrefixOf s st then Just() else Nothing
   in (RS (s++" ") readit , drop (length s) st))



data P = I Int | S String deriving (Read, Show)

instance   ParseLet P String where
    parse mpx  =   I <$> (str "I" *> pString (sel (\(I x) -> x) mpx ))
              <|>  S <$> (str "S" *> pString (sel (\(S s) -> s) mpx ))

main =  do
   putStrLn . serial $ S "hi"
   print (deserial "I 2" :: Maybe P )


Sunday, July 01, 2012

From Monads to Monoids in a small category


(Added 06/09/12: clarification about the nature of ' m a' from the point of view of C.Theory)

Let's start with the definition of a small category with a morphism defined by 'm' between set of objects 'a' and 'm b'. The simplest category definition would be:

{-# LANGUAGE FlexibleInstances #-}
import Data.Monoid
import Control.Monad

class Category  m a b where
 morph:: a ->  m b


Here 'm b'  is the codomain of the morphism which depends on the category instance. More on this at the end of the post. .

The other two requisites for a category according with this are an identity operation and associativity of the morphism. The first is guaranteed in Haskell by the polymorphic function 'id'.


id :: a -> a
id x = x

Lett´s modify the signature of 'id' slightly to match the Category definition as such:

return :: a -> m a

The second condition, associativity, is guaranteed by the nature of the forward chaining of operations in any programming language. (if not where that way, it would be impossible the denotational semantics of imperative languages in terms of monads, I guess)



The definition of functor According to this :



Let C and D be categories. A functor F from C to D is a mapping that:

  • associates to each object  an object ,
  • associates to each morphism  a morphism


So the morphism (a -> m b) may meet the first condition. This morphism  maps elements from the set ‘a’ to elements in the set ‘m b’. The second condition is the one defined in the Haskell instance of functor:


instance Functor a where

 fmap :: (a -> b) -> (m a ->  m b)


When a and b are the same, then we have a functor.which maps elements in ‘a’ to elements in ‘m a’  (a -> m a). But are 'a' and 'm a' the same? It seems that it is not the case, but I will talk about it later.

The functor category has functors as elements and natural transformations as morphisms, Additionally, the functors have a double nature as maps between points in ‘a’ (a -> ma) and as maps between morphisms (fmap) .  But a monoid is defined over elements of the set, and a monad works with morphisms (a -> m b), so we are interested on the set of elements with signature  (a -> m a) , to describe the Monoid instance for these elements.


If we try to construct the Monoid instance for any morphisms (a -> m a) . This instance demands that 'm' is a monad, that is, that the morphisms of m must  compose according with the monad laws:


instance Monad m => Monoid  (a -> m a) where
   mappend f g= \x -> do
                          y <-  f x
                          g y
   mempty=   \x -> return x

The definition of mappend is equivalent to the Kleisli operator in a Monad

(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)
f >=> g = \x -> f x >>= g


In this case, a b and c are the same sets:

The Monoid instance e of morphisms that meet the Monad laws can be written as:

instance Monad m => Monoid  (a -> m a) where
   mappend = (>=>)
   mempty  = return

This typechecks in Haskell. But does this set (a -> m a) of maps between elements from the endofunctors have the necessary  reflexive and associative properties for being a Monoid? If you compare (1) the asociativite and identity laws of a Monoid, when applied to the morphisms between (a -> m a)  objects,  with (2) the monad laws you will conclude that (1) and (2)  are identical, and thus only the monadic morohisms form a Monoid,

The Monoid is defined within the subset of morphisms (a -> m a) which are part of the functor category, not with the set 'a' as such.  The return operation in a Monad correspond with the identity morphism in the set of such  morphisms. 



While in the IO monad, the morphisms (a -> IO a) refer to the same set ‘a’ in the domain and the codomain, (a -> Maybe a)  has one additional element (Nothing) which is terminal. 

In the case of List monad, the morphisms of the monad (a -> [a]) 'm a' is [a]. It sems quite different at first sight, But a list, as seen from the point of view of the list category, is a list of alternative arrows in the set 'a' (see the previous post).

for example the expression

f :: String -> [String]
f x= take 5 $ repeat x

can be considered as a endomorphism in the set of Strings that has five arrows. Then 'f' can be considered as a morphisn from 'a' to the set 'a' plus the empty list element (which is terminal)

'What is 'm a’ ?. Seen from the point of view of category theory, it is 'a' plus some terminal element(s).

What about the generalization for the morphisms of any ( a -> m b) being a and b of any kind? The Monoid instance can be extended to a larger class of morphisms between any Typeabe objects by assuming a of type Dynamic. So implicitly, to any a -> m b as long as a and b are Typeable:


instance Monad m => Monoid  (Dynamic -> m Dynamic) where
   mappend = (>=>)
   mempty  = return
If any 'a' with morphisms (a -> m a) is a Category, Then, I guess, the set of Typeable objects with the morphisms (Dynamic -> m Dynamic) is a Category

Even it can be extended to the endofunctors of the set of elements of any type:

data AllTypes = forall a . AllTypes a


instance Monad m => Monoid  (AllTypes-> m AllTypes) where
   mappend = (>=>)
   mempty  = return


Which implicity is a Monoid instance for any (a -> m b)

Am I wrong?. Did I miss something?