@@ -0,0 +1,263 @@
1+{-# LANGUAGE TypeFamilies #-}
2+{-# LANGUAGE TupleSections #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE DefaultSignatures #-}
6+{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE FunctionalDependencies #-}
11+import Prelude hiding (id, (.), take, takeWhile)
13+import Control.Applicative
15+import Control.Category
16+import Control.Lens hiding (imap, _Cons)
18+import qualified Data.Attoparsec.Text as Text
19+import Data.Attoparsec.Types
21+import Data.Functor.Identity
22+import Data.MonoTraversable
23+import Data.Sequences hiding (take, takeWhile)
24+import Data.Text (Text)
30+-- | Isomorphism in the kleisli category of some monad.
31+data KleisliIso m a b = KleisliIso (Kleisli m a b) (Kleisli m b a)
33+instance Monad m => Category (KleisliIso m) where
34+ id = KleisliIso id id
35+ (KleisliIso f g) . (KleisliIso f' g') = KleisliIso (f . f') (g' . g)
37+isoK :: (a -> m b) -> (b -> m a) -> KleisliIso m a b
38+isoK f g = KleisliIso (Kleisli f) (Kleisli g)
40+apply :: KleisliIso m a b -> a -> m b
41+apply (KleisliIso (Kleisli f) _) = f
43+unapply :: KleisliIso m a b -> b -> m a
44+unapply (KleisliIso _ (Kleisli g)) = g
46+from :: KleisliIso m a b -> KleisliIso m b a
47+from (KleisliIso f g) = KleisliIso g f
49+unit :: Monad m => KleisliIso m (a, ()) a
50+unit = isoK (return . fst) (return . (, ()))
52+symmetry :: Monad m => KleisliIso m (a, b) (b, a)
54+ where f (a, b) = return (b, a)
56+equalTo :: (Eq a, Monad m) => a -> KleisliIso m a ()
59+ f y | x == y = return ()
60+ | otherwise = fail "equalTo: not equal"
63+oneWayConst :: Monad m => a -> KleisliIso m a ()
64+oneWayConst x = isoK f g
69+check :: Monad m => (a -> Bool) -> KleisliIso m a a
71+ where f x | p x = return x
72+ | otherwise = fail "check: predicate failed"
74+packed :: (Monad m, IsSequence seq) => KleisliIso m [Element seq] seq
75+packed = isoK (return . fromList) (return . otoList)
77+-- | Isomorphism between unit and empty list.
78+_Nil :: Monad m => KleisliIso m () [a]
83+ g _ = fail "expected empty list"
85+-- | Isomorphism between (head, tail) and a non empty list.
86+_Cons :: Monad m => KleisliIso m (a, [a]) [a]
89+ f (x, xs) = return (x:xs)
90+ g (x:xs) = return (x, xs)
91+ g _ = fail "expected non-empty list"
93+-- | A functor from the category of isomorphisms of the Kleisli category
94+-- of some monad to Hask.
95+class IsoFunctor f where
96+ imap :: KleisliIso Identity a b -> f a -> f b
97+ imapK :: KleisliIso m a b -> f a -> f (m b)
99+(/$/) :: IsoFunctor f => KleisliIso Identity a b -> f a -> f b
102+class IsoFunctor f => IsoPointed f where
106+ ipure :: KleisliIso Identity () a -> f a
109+ ipureK :: KleisliIso m () a -> f (m a)
110+ ipureK = (`imapK` iunit)
112+ {-# MINIMAL iunit | ipure #-}
114+class IsoFunctor f => IsoFail f where
115+ ifail :: String -> f a
117+class IsoPointed f => IsoApply f where
118+ (/*/) :: f a -> f b -> f (a, b)
120+ (/*) :: f a -> f () -> f a
121+ f /* g = unit /$/ f /*/ g
123+ (*/) :: f () -> f b -> f b
124+ f */ g = unit . symmetry /$/ f /*/ g
126+ {-# MINIMAL (/*/) #-}
128+class IsoApply f => IsoAlternative f where
130+ (/|/) :: f a -> f a -> f a
132+ isome :: f a -> f [a]
133+ isome v = _Cons /$/ v /*/ imany v
135+ imany :: f a -> f [a]
136+ imany v = isome v /|/ ipure _Nil
138+ sepBy :: f a -> f () -> f [a]
139+ sepBy v s = sepBy1 v s /|/ ipure _Nil
141+ sepBy1 :: f a -> f () -> f [a]
142+ sepBy1 v s = _Cons /$/ v /* s /*/ sepBy v s
144+ {-# MINIMAL iempty, (/|/) #-}
146+class (IsoAlternative syn, IsoFail syn) => Syntax syn seq | syn -> seq where
147+ joinErr :: syn (Either String a) -> syn a
149+ anyChar :: syn (Element seq)
151+ char :: Element seq -> syn ()
152+ default char :: Eq (Element seq) => Element seq -> syn ()
153+ char c = equalTo c /$/ anyChar
155+ satisfy :: (Element seq -> Bool) -> syn (Element seq)
156+ satisfy p = joinErr (imapK (check p) anyChar)
158+ string :: seq -> syn ()
159+ default string :: (IsSequence seq, Eq seq) => seq -> syn ()
160+ string s = equalTo s /$/ take (olength s)
162+ take :: Int -> syn seq
163+ default take :: IsSequence seq => Int -> syn seq
164+ take n = packed /$/ ireplicate n anyChar
166+ takeWhile :: (Element seq -> Bool) -> syn seq
167+ default takeWhile :: IsSequence seq => (Element seq -> Bool) -> syn seq
168+ takeWhile p = packed /$/ imany (satisfy p)
170+ takeWhile1 :: (Element seq -> Bool) -> syn seq
171+ default takeWhile1 :: IsSequence seq => (Element seq -> Bool) -> syn seq
172+ takeWhile1 p = packed /$/ isome (satisfy p)
174+ {-# MINIMAL joinErr, anyChar #-}
176+ireplicate :: IsoApply f => Int -> f a -> f [a]
177+ireplicate 0 _ = ipure _Nil
178+ireplicate n m = _Cons /$/ m /*/ ireplicate (n-1) m
180+isequence :: IsoApply f => [f a] -> f [a]
181+isequence [] = ipure _Nil
182+isequence (x:xs) = _Cons /$/ x /*/ isequence xs
184+skipSpace :: (Syntax syn seq, IsSequence seq, Element seq ~ Char) => syn ()
185+skipSpace = oneWayConst (fromList []) /$/ takeWhile isSpace
187+skipSpace1 :: (Syntax syn seq, IsSequence seq, Element seq ~ Char) => syn ()
188+skipSpace1 = oneWayConst (singleton ' ') /$/ takeWhile1 isSpace
190+-- Attoparsec implementation.
192+instance IsoFunctor (Parser i) where
193+ imap i m = fmap (runIdentity . apply i) m
194+ imapK i m = fmap (apply i) m
196+instance IsoFail (Parser i) where
199+instance IsoPointed (Parser i) where
200+ ipure = pure . runIdentity . (`apply` ())
202+instance IsoApply (Parser i) where
203+ f /*/ g = (,) <$> f <*> g
205+instance IsoAlternative (Parser i) where
211+ sepBy1 = Text.sepBy1
213+instance Syntax (Parser Text) Text where
214+ joinErr = (>>= either fail return)
215+ anyChar = Text.anyChar
216+ satisfy = Text.satisfy
217+ char = void . Text.char
218+ string = void . Text.string
219+ takeWhile = Text.takeWhile
220+ takeWhile1 = Text.takeWhile1
229+_Var :: Monad m => KleisliIso m Text AST
233+ g (Var t) = return t
234+ g _ = fail "expected a Var"
236+_App :: Monad m => KleisliIso m (AST, AST) AST
239+ f = return . uncurry App
240+ g (App h x) = return (h, x)
241+ g _ = fail "expected an App"
243+_Abs :: Monad m => KleisliIso m (Text, AST) AST
246+ f = return . uncurry Abs
247+ g (Abs n b) = return (n, b)
248+ g _ = fail "expected an Abs"
250+name :: Syntax syn Text => syn Text
251+name = takeWhile1 isAlphaNum
253+atom :: Syntax syn Text => syn AST
255+ /|/ char '(' */ expr /* char ')'
257+expr :: Syntax syn Text => syn AST
258+expr = _App /$/ atom /* skipSpace1 /*/ atom
259+ /|/ _Abs /$/ char '\\' /* skipSpace
260+ */ name /* skipSpace
261+ /* string "->" /* skipSpace