Copperbox revision 1112.
I've added some Kure boilerplate to make traversals more systematic, however it might not stay in for long as I've decided I don't want overlays in the syntax tree. Moving overlays to a post-processing step will simplify things and possibly remove the need for complicated traversals.
Saturday, January 30, 2010
Friday, January 29, 2010
KURE
I've been using Andy Gill's KURE, unfortunately there aren't many examples on the web. Here are two versions of Company the SYB example. One version has handwritten bolierplate, they other uses kure-your-boilerplate. The Template Haskell generated by kyb has problems with the monomorphism restriction - it needs to be turned off, otherwise there will be type errors for crushU. Also the Generic union type - here CGeneric - needs a (hand-coded) instance of Term where the Generic is its own Generic root!
Here's a version with handwritten boilerplate, note that the Generic union type (CGeneric) needs a Walker instance just like the other types:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# OPTIONS -Wall #-}
-- NOTE - without NoMonomorphismRestriction, the generated
-- function crushU has type errors
module Company where
import Language.KURE
import Language.KURE.Boilerplate
import Control.Monad
import Control.Monad.Identity
import Data.Monoid
data Company = C [Dept] deriving (Eq, Show)
data Dept = D Name Manager [Unt] deriving (Eq, Show)
data Unt = PU Employee | DU Dept deriving (Eq, Show)
data Employee = E Person Salary deriving (Eq, Show)
data Person = P Name Address deriving (Eq, Show)
data Salary = S Float deriving (Eq, Show, Ord)
type Manager = Employee
type Name = String
type Address = String
-- An illustrative company
genCom :: Company
genCom = C [D "Research" joe [PU mike, PU kate],
D "Strategy" mary []]
joe, mike, kate, mary :: Employee
joe = E (P "Joe" "Oregon") (S 8000)
mike = E (P "Mike" "Boston") (S 1000)
kate = E (P "Kate" "San Diego") (S 2000)
mary = E (P "Mary" "Washington") (S 100000)
data CGeneric = GCompany Company
| GDept Dept
| GUnt Unt
| GEmployee Employee
| GPerson Person
| GSalary Salary
instance Term Company where
type Generic Company = CGeneric
inject = GCompany
select (GCompany a) = Just a
select _ = Nothing
instance Term Dept where
type Generic Dept = CGeneric
inject = GDept
select (GDept a) = Just a
select _ = Nothing
instance Term Unt where
type Generic Unt = CGeneric
inject = GUnt
select (GUnt a) = Just a
select _ = Nothing
instance Term Employee where
type Generic Employee = CGeneric
inject = GEmployee
select (GEmployee a) = Just a
select _ = Nothing
instance Term Person where
type Generic Person = CGeneric
inject = GPerson
select (GPerson a) = Just a
select _ = Nothing
instance Term Salary where
type Generic Salary = CGeneric
inject = GSalary
select (GSalary a) = Just a
select _ = Nothing
instance Term CGeneric where
type Generic CGeneric = CGeneric -- CGeneric is its own Generic root.
inject = id
select e = return e
$(kureYourBoilerplate ''CGeneric [(''Identity, ''())])
incS :: Float -> Salary -> Salary
incS k (S s) = S (s * (1+k))
--- Increase salary
-- increase everyone's salary by 10%, topdown.
-- transformer, non-contextual, full, topdown, left-to-right
-- f1 :: Data t => Float -> t -> Maybe t
-- f1 k = traverse Trans NoCtx Full FromTop FromLeft (always $ incS k)
rewriteStep :: Float -> Rewrite Identity () Salary
rewriteStep k = rewrite $ \ e -> return (incS k e)
f1 :: (CGeneric ~ Generic exp, Term exp)
=> Float -> Rewrite Identity () exp
f1 k = extractR $ topdownR $ tryR $ promoteR (rewriteStep k)
demo1 :: IO ()
demo1 = do
print $ runIdentity $ runRewrite (f1 0.10) () genCom
print $ runIdentity $ runRewrite (f1 0.10) () joe
print $ runIdentity $ runRewrite (f1 0.10) () (S 10000.0)
Here's a version with handwritten boilerplate, note that the Generic union type (CGeneric) needs a Walker instance just like the other types:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS -Wall #-}
module Company where
import Language.KURE
import Control.Monad
import Control.Monad.Identity
import Data.Monoid
data Company = C [Dept] deriving (Eq, Show)
data Dept = D Name Manager [Unt] deriving (Eq, Show)
data Unt = PU Employee | DU Dept deriving (Eq, Show)
data Employee = E Person Salary deriving (Eq, Show)
data Person = P Name Address deriving (Eq, Show)
data Salary = S Float deriving (Eq, Show, Ord)
type Manager = Employee
type Name = String
type Address = String
-- An illustrative company
genCom :: Company
genCom = C [D "Research" joe [PU mike, PU kate],
D "Strategy" mary []]
joe, mike, kate, mary :: Employee
joe = E (P "Joe" "Oregon") (S 8000)
mike = E (P "Mike" "Boston") (S 1000)
kate = E (P "Kate" "San Diego") (S 2000)
mary = E (P "Mary" "Washington") (S 100000)
data CGeneric = GCompany Company
| GDept Dept
| GUnt Unt
| GEmployee Employee
| GPerson Person
| GSalary Salary
instance Term Company where
type Generic Company = CGeneric
inject = GCompany
select (GCompany a) = Just a
select _ = Nothing
instance Term Dept where
type Generic Dept = CGeneric
inject = GDept
select (GDept a) = Just a
select _ = Nothing
instance Term Unt where
type Generic Unt = CGeneric
inject = GUnt
select (GUnt a) = Just a
select _ = Nothing
instance Term Employee where
type Generic Employee = CGeneric
inject = GEmployee
select (GEmployee a) = Just a
select _ = Nothing
instance Term Person where
type Generic Person = CGeneric
inject = GPerson
select (GPerson a) = Just a
select _ = Nothing
instance Term Salary where
type Generic Salary = CGeneric
inject = GSalary
select (GSalary a) = Just a
select _ = Nothing
instance Term CGeneric where
type Generic CGeneric = CGeneric -- CGeneric is its own Generic root.
inject = id
select e = return e
instance (Monoid dec, Monad m) => Walker m dec Company where
allR rr = companyR (extractR rr)
crushU rr = companyU (extractU rr)
companyR :: (Monoid dec, Monad m)
=> Rewrite m dec Dept -> Rewrite m dec Company
companyR rr = transparently $ translate $ \ (C xs) ->
liftM C (mapM (apply rr) xs)
companyU :: (Monad m, Monoid dec, Monoid r)
=> Translate m dec Dept r -> Translate m dec Company r
companyU rr = translate $ \ (C xs) ->
liftM mconcat $ mapM (apply rr) xs
instance (Monoid dec, Monad m) => Walker m dec Dept where
allR rr = deptR (extractR rr) (extractR rr)
crushU rr = deptU (extractU rr) (extractU rr)
deptR :: (Monoid dec, Monad m)
=> Rewrite m dec Employee -> Rewrite m dec Unt -> Rewrite m dec Dept
deptR rr1 rr2 = transparently $ translate $ \ (D name m us) ->
liftM2 (D name) (apply rr1 m) (mapM (apply rr2) us)
deptU :: (Monad m, Monoid dec, Monoid r)
=> Translate m dec Employee r -> Translate m dec Unt r
-> Translate m dec Dept r
deptU rr1 rr2 = translate $ \ (D _ a xs) ->
liftM2 mappend (apply rr1 a) (liftM mconcat (mapM (apply rr2) xs))
instance (Monoid dec, Monad m) => Walker m dec Unt where
allR rr = puR (extractR rr)
<+ duR (extractR rr)
crushU rr = puU (extractU rr)
<+ duU (extractU rr)
puR :: (Monoid dec, Monad m)
=> Rewrite m dec Employee -> Rewrite m dec Unt
puR rr = transparently $ translate $ \ e -> case e of
PU e1 -> liftM PU (apply rr e1)
_ -> fail "puR"
puU :: (Monad m, Monoid dec, Monoid r)
=> Translate m dec Employee r -> Translate m dec Unt r
puU rr = translate $ \ e -> case e of
PU e1 -> apply rr e1
_ -> fail "puU"
duR :: (Monoid dec, Monad m)
=> Rewrite m dec Dept -> Rewrite m dec Unt
duR rr = transparently $ translate $ \ e -> case e of
DU d1 -> liftM DU (apply rr d1)
_ -> fail "duR"
duU :: (Monad m, Monoid dec, Monoid r)
=> Translate m dec Dept r -> Translate m dec Unt r
duU rr = translate $ \ e -> case e of
DU d1 -> apply rr d1
_ -> fail "duU"
instance (Monoid dec, Monad m) => Walker m dec Employee where
allR rr = employeeR (extractR rr) (extractR rr)
crushU rr = employeeU (extractU rr) (extractU rr)
employeeR :: (Monoid dec, Monad m)
=> Rewrite m dec Person -> Rewrite m dec Salary
-> Rewrite m dec Employee
employeeR rr1 rr2 = transparently $ translate $ \ (E p s) ->
liftM2 E (apply rr1 p) (apply rr2 s)
employeeU :: (Monad m, Monoid dec, Monoid r)
=> Translate m dec Person r -> Translate m dec Salary r
-> Translate m dec Employee r
employeeU rr1 rr2 = translate $ \ (E p s) ->
liftM2 mappend (apply rr1 p) (apply rr2 s)
instance (Monoid dec, Monad m) => Walker m dec Person where
allR _ = personR
crushU _ = personU
personR :: (Monoid dec, Monad m)
=> Rewrite m dec Person
personR = transparently $ rewrite $ return
personU :: (Monad m, Monoid dec, Monoid r)
=> Translate m dec Person r
personU = translate $ \ _ -> return mempty
instance (Monoid dec, Monad m) => Walker m dec Salary where
allR _ = salaryR
crushU _ = salaryU
salaryR :: (Monoid dec, Monad m)
=> Rewrite m dec Salary
salaryR = transparently $ rewrite $ return
salaryU :: (Monad m, Monoid dec, Monoid r)
=> Translate m dec Salary r
salaryU = translate $ \ _ -> return mempty
instance (Monoid dec, Monad m) => Walker m dec CGeneric where
allR rr = promoteR (companyR (extractR rr))
<+ promoteR (deptR (extractR rr) (extractR rr))
<+ promoteR (puR (extractR rr) <+ duR (extractR rr))
<+ promoteR (employeeR (extractR rr) (extractR rr))
<+ promoteR personR
<+ promoteR salaryR
crushU rr = promoteU (companyU (extractU rr))
<+ promoteU (deptU (extractU rr) (extractU rr))
<+ promoteU (puU (extractU rr) <+ duU (extractU rr))
<+ promoteU (employeeU (extractU rr) (extractU rr))
<+ promoteU personU
<+ promoteU salaryU
incS :: Float -> Salary -> Salary
incS k (S s) = S (s * (1+k))
--- Increase salary
-- increase everyone's salary by 10%, topdown.
-- transformer, non-contextual, full, topdown, left-to-right
-- f1 :: Data t => Float -> t -> Maybe t
-- f1 k = traverse Trans NoCtx Full FromTop FromLeft (always $ incS k)
rewriteStep :: (Monad m, Monoid dec) => Float -> Rewrite m dec Salary
rewriteStep k = rewrite $ \ e -> return (incS k e)
f1 :: (Monad m, Monoid dec, Term exp, CGeneric ~ Generic exp)
=> Float -> Rewrite m dec exp
f1 k = extractR $ topdownR $ tryR $ promoteR (rewriteStep k)
demo1 :: IO ()
demo1 = do
print $ runIdentity $ runRewrite (f1 0.10) () genCom
print $ runIdentity $ runRewrite (f1 0.10) () joe
print $ runIdentity $ runRewrite (f1 0.10) () (S 10000.0)
Wednesday, January 27, 2010
Mullein M2
Copperbox revision 1111.
More work on M2, Mullein's successor. I've added some of the LilyPond code from Mullein, though much of it is commented out as I haven't looked at the translation code yet.
More work on M2, Mullein's successor. I've added some of the LilyPond code from Mullein, though much of it is commented out as I haven't looked at the translation code yet.
data-aviary
Copperbox revision 1110.
I've added a new Birds module with revised type signatures, I think the new naming scheme is a bit clearer.
I've added a new Birds module with revised type signatures, I think the new naming scheme is a bit clearer.
Tuesday, January 26, 2010
Monday, January 25, 2010
Mullein M2
Copperbox revision 1108.
Initial work on a new version of Mullein, provisionally called M2 - I'll give it a distinct new name once I think of a good one.
I don't really want work on the old code and still call it Mullein as a lot of code needs to change and I always find it dispiriting working with a sandbox where much of the code is broken. The syntax tree needs significant changes to accommodate triplets and duplets, plus I don't like the way I previously handled updating traversals on the old tree.
Initial work on a new version of Mullein, provisionally called M2 - I'll give it a distinct new name once I think of a good one.
I don't really want work on the old code and still call it Mullein as a lot of code needs to change and I always find it dispiriting working with a sandbox where much of the code is broken. The syntax tree needs significant changes to accommodate triplets and duplets, plus I don't like the way I previously handled updating traversals on the old tree.
Friday, January 22, 2010
Hurdle and Kangaroo
Copperbox revision 1107.
I've made new release archives, while I'm not sure how much work I want to put into them the existing versions on Hackage aren't very good, so they merit improving.
I've made new release archives, while I'm not sure how much work I want to put into them the existing versions on Hackage aren't very good, so they merit improving.
Thursday, January 21, 2010
Hurdle, SFont and Kangaroo
Copperbox revision 1102.
Updates to Hurdle and SFont to make them run with the latest Kangaroo.
SFont will need its naming changing in due course as there is another project called SFont.
Updates to Hurdle and SFont to make them run with the latest Kangaroo.
SFont will need its naming changing in due course as there is another project called SFont.
kangaroo
Copperbox revision 1101.
I've sorted out the region boundary problem that was causing the MIDI reader to fail. The nub was that I hadn't really thought about whether the region start and end values were inclusive or not. Once I realized I hadn't thought about this it was easy to consider them to be inclusive (the right choice) and change the region creation code accordingly.
I've sorted out the region boundary problem that was causing the MIDI reader to fail. The nub was that I hadn't really thought about whether the region start and end values were inclusive or not. Once I realized I hadn't thought about this it was easy to consider them to be inclusive (the right choice) and change the region creation code accordingly.
kangaroo
Copperbox revision 1098.
Some work on regions, though not much progress. I've made cursor moving failure-free whether or not a move puts the cursor past the end of file. I tried encoding end-of-file as a constructor in the Pos data type but it added complexity rather than unanimously improving correctness.
Some work on regions, though not much progress. I've made cursor moving failure-free whether or not a move puts the cursor past the end of file. I tried encoding end-of-file as a constructor in the Pos data type but it added complexity rather than unanimously improving correctness.
Wednesday, January 20, 2010
kangaroo
Copperbox revision 1097.
I've improved the region handling with better error reporting. The parse monad still has a boundary error when it reaches the end of a region - maybe I'll have to extend the position type so it explicitly represents EOF / EOR (end-of-region).
I've improved the region handling with better error reporting. The parse monad still has a boundary error when it reaches the end of a region - maybe I'll have to extend the position type so it explicitly represents EOF / EOR (end-of-region).
Tuesday, January 19, 2010
data-aviary
Copperbox revision 1095.
Completed all the specializations for Data.Aviary.Functional - Applicative, Monad, Category, Arrow and Comonad. Made a new release archive.
Completed all the specializations for Data.Aviary.Functional - Applicative, Monad, Category, Arrow and Comonad. Made a new release archive.
Monday, January 18, 2010
data-aviary
Copperbox revision 1094.
I've added a new module to Data-Aviary that specializes operations from Applicative, Monad etc. to the function type. This might be useful for spotting patterns in the type signatures of the operations that might not be obvious in their more general (type-class) type.
For instance to work with records I have a family of 'substs' - extended arity versions of the S (Starling) combinator:
Now because I don't use them too often, when I go back to them I'll often think "Oh, they're just liftA2, liftA3" and swap them in the code introducing new type errors everywhere. I tend to forget that liftA2, liftA3 are a family of S' combinators rather than S combinators:
I've added a new module to Data-Aviary that specializes operations from Applicative, Monad etc. to the function type. This might be useful for spotting patterns in the type signatures of the operations that might not be obvious in their more general (type-class) type.
For instance to work with records I have a family of 'substs' - extended arity versions of the S (Starling) combinator:
subst :: (r -> a -> b) -> (r -> a) -> r -> b
subst f g x = f x (g x)
subst2 :: (r -> a -> b -> c) -> (r -> a) -> (r -> b) -> r -> c
subst2 f g h x = f x (g x) (h x)
subst3 :: (r -> a -> b -> c -> d) -> (r -> a) -> (r -> b) -> (r -> c) -> r -> d
subst3 f g h i x = f x (g x) (h x) (i x)
Now because I don't use them too often, when I go back to them I'll often think "Oh, they're just liftA2, liftA3" and swap them in the code introducing new type errors everywhere. I tend to forget that liftA2, liftA3 are a family of S' combinators rather than S combinators:
liftA :: (a -> b) -> (r -> a) -> r -> b
liftA2 :: (a -> b -> c) -> (r -> a) -> (r -> b) -> r -> c
liftA3 :: (a -> b -> c -> d) -> (r -> a) -> (r -> b) -> (r -> c) -> r -> d
Sunday, January 17, 2010
OpenVG binding
Copperbox revision 1093.
I've made new releases with the improvements to the Image, Paths and RenderingQuality modules.
Versions are: OpenVG-0.6.0, OpenVGRaw-0.2.0
I've made new releases with the improvements to the Image, Paths and RenderingQuality modules.
Versions are: OpenVG-0.6.0, OpenVGRaw-0.2.0
OpenVG binding
Copperbox revision 1092.
I've revised the Image module so it no longer exports functions with raw pointers in their signatures for pixel data. Instead pixel data is encapsulated in an opaque type.
That said - the PixelData type as currently implemented might not be sufficient to actually use. Particularly, I don't quite see where to actually create PixelData.
I've revised the Image module so it no longer exports functions with raw pointers in their signatures for pixel data. Instead pixel data is encapsulated in an opaque type.
That said - the PixelData type as currently implemented might not be sufficient to actually use. Particularly, I don't quite see where to actually create PixelData.
OpenVG binding
Copperbox revision 1091.
The opaque matrix type is now used in in the interface of the RenderingQuality module, none of the functions export a pointer type any more (some other modules in the higher level package still export raw pointers and these need work). The matrix is marshalled in and out with a list to follow HOpenGL's example however it might be better to define a simple 3x3 matrix type.
OpenVGRaw had a bad type signature for vgGetMatrix, so I've corrected that.
The opaque matrix type is now used in in the interface of the RenderingQuality module, none of the functions export a pointer type any more (some other modules in the higher level package still export raw pointers and these need work). The matrix is marshalled in and out with a list to follow HOpenGL's example however it might be better to define a simple 3x3 matrix type.
OpenVGRaw had a bad type signature for vgGetMatrix, so I've corrected that.
Saturday, January 16, 2010
OpenVG binding
Copperbox revision 1090.
Initial work adding an opaque and safe matrix type. The code is derived from the Matrix type class in HOpenGL but as matrices are simpler in OpenVG I don't need a type class (there is only one matrix type).
Initial work adding an opaque and safe matrix type. The code is derived from the Matrix type class in HOpenGL but as matrices are simpler in OpenVG I don't need a type class (there is only one matrix type).
OpenVG binding
Copperbox revision 1089.
Release archives for OpenVG-0.5.0 and OpenVGRaw-0.1.0. Some minor formatting changes to modules in OpenVG that had been pending a commit since before the new year.
Release archives for OpenVG-0.5.0 and OpenVGRaw-0.1.0. Some minor formatting changes to modules in OpenVG that had been pending a commit since before the new year.
Friday, January 15, 2010
precis
Copperbox revisions 1087 & 1088.
I've decided to use Cabal's machinery to parse cabal files even though I only want a few fields. The structure of cabal files is more complex than I thought, plus I couldn't make a good formulation of island parsing (and I've tried many times).
I've decided to use Cabal's machinery to parse cabal files even though I only want a few fields. The structure of cabal files is more complex than I thought, plus I couldn't make a good formulation of island parsing (and I've tried many times).
Thursday, January 14, 2010
precis
Copperbox revision 1085.
Maybe this will be a bad idea, but I've started implementing a Haskell lexer with Parsec. I'm not bothered about performance so I don't mind Parsec on that score; but I am a bit concerned that the lexer spec in the H98 report relies on longest match - this might not be easily achievable with parser combinators.
Revision 1086 - deleted a wrongly created directory.
Maybe this will be a bad idea, but I've started implementing a Haskell lexer with Parsec. I'm not bothered about performance so I don't mind Parsec on that score; but I am a bit concerned that the lexer spec in the H98 report relies on longest match - this might not be easily achievable with parser combinators.
Revision 1086 - deleted a wrongly created directory.
Wednesday, January 13, 2010
Tuesday, January 12, 2010
Monday, January 11, 2010
precis
Copperbox revision 1081.
I've added a new project: Precis. The aim is to produce summaries of Cabal projects. The recent work on zparse was to make it capable for writing 'fact extracting' parsers, but I've decided to go with Parsec instead. I don't yet have Parsec code to extract facts and ignore 'water' but I've written the line- and indent-sensitive combinators that I was trying to do in zparse.
I've added a new project: Precis. The aim is to produce summaries of Cabal projects. The recent work on zparse was to make it capable for writing 'fact extracting' parsers, but I've decided to go with Parsec instead. I don't yet have Parsec code to extract facts and ignore 'water' but I've written the line- and indent-sensitive combinators that I was trying to do in zparse.
Sunday, January 10, 2010
zparse
Copperbox revision 1080.
Changes to the Parse type - it no longer returns unconsumed input (unconsumed input is available at the end of parse, as it is in the state). I've only come up with one usefully different combinator to Parsec though (withinLine) and I could code this in Parsec quite easily. So I don't think I'm going in the right direction...
Changes to the Parse type - it no longer returns unconsumed input (unconsumed input is available at the end of parse, as it is in the state). I've only come up with one usefully different combinator to Parsec though (withinLine) and I could code this in Parsec quite easily. So I don't think I'm going in the right direction...
Saturday, January 9, 2010
Friday, January 8, 2010
zparse
Copperbox revision 1076.
I've filled out the Lexical module, so to some degree the easy bits are now in place (with a caveat that ParseError, at least, doesn't work properly). The tough parts are next - like stacking lexical (character consuming) parsers with token consuming parsers.
I've filled out the Lexical module, so to some degree the easy bits are now in place (with a caveat that ParseError, at least, doesn't work properly). The tough parts are next - like stacking lexical (character consuming) parsers with token consuming parsers.
Thursday, January 7, 2010
resumptions
More resumptions, here's a translation of the code from Andrzej Filinski's 'Representing Layered Monads'. I think the translation is accurate, except par in the version below has deterministic scheduling:
{-# OPTIONS -Wall #-}
module FilinskiConc where
data ResT m a = Done a | Susp (m (ResT m a))
instance Monad m => Monad (ResT m) where
return = Done
(Done v) >>= f = f v
(Susp r) >>= f = Susp (r >>= \k -> return (k >>= f))
step :: Monad m => m a -> ResT m a
step x = Susp $ x >>= (return . Done)
yield :: Monad m => ResT m ()
yield = Susp (return (return ()))
pOr :: Monad m => ResT m Bool -> ResT m Bool -> ResT m Bool
pOr (Done True) _ = Done True
pOr (Done False) p = p
pOr (Susp t1) t2 = Susp $ t1 >>= \r -> return (pOr t2 r)
atomically :: Monad m => ResT m a -> ResT m a
atomically = work `flip` False where
work (Done a) False = step (return a)
work (Done a) True = Done a
work (Susp t) _ = do { a <- step t ; work a True }
-- Unlike Filinkski's 'par' the 'par' here has a deterministic
-- scheduler - we do one step of a and one step of b at each
-- turn.
--
par :: Monad m => ResT m a -> ResT m b -> ResT m (a,b)
par (Done a) (Done b) = Done (a,b)
par (Done a) (Susp tb) = Susp $ tb >>= \r -> return (r >>= \b -> Done (a,b))
par (Susp ta) (Done b) = Susp $ ta >>= \r -> return (r >>= \a -> Done (a,b))
par (Susp ta) (Susp tb) = do { a <- step ta; b <- step tb; par a b }
run :: Monad m => ResT m a -> m a
run (Susp phi) = phi >>= run
run (Done v) = return v
demo1 :: IO ((),())
demo1 = run (par (step $ putStrLn "a") (step $ putStrLn "b"))
demo2 :: IO Bool
demo2 = run (pOr (step $ do { putStrLn "a"; return False} )
(step $ do { putStrLn "b"; return True} ))
asteps, bsteps :: ResT IO [()]
asteps = mapM (step . putChar) "aaaaaaa"
bsteps = mapM (step . putChar) "bbbbb"
demo3 :: IO ([()],[()])
demo3 = run (par asteps bsteps)
Wednesday, January 6, 2010
resumptions
I can't seem to find enough examples of using resumption monads for my taste.
Here is the code from William Harrison et al's code from 'Asynchronous Exceptions As An Effect' re-written with standard machinery (i.e. with monads from mtl).
--
Here is the code from William Harrison et al's code from 'Asynchronous Exceptions As An Effect' re-written with standard machinery (i.e. with monads from mtl).
--
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS -Wall #-}
module AsyncE where
import Control.Monad.Error
merge :: [[a]] -> [a]
merge = concat
data Err = Error
deriving Show
instance Error Err where
noMsg = Error
strMsg = const Error
data ResT m a = Done a | Pause (m (ResT m a))
instance Monad m => Monad (ResT m) where
return = Done
Done v >>= f = f v
Pause phi >>= f = Pause $ phi >>= \k -> return (k >>= f)
type N a = [a]
type R = ResT E
type E = ErrorT Err []
instance Show a => Show (E a) where
show = show . runErrorT
instance Show a => Show (R a) where
show (Done a) = "Done " ++ show a
show (Pause phi) = "Pause " ++ show phi
ok :: a -> Either Err a
ok = Right
err :: Either Err a
err = Left Error
-- page 7 examples
ex1 :: N Int
ex2 :: E Int
ex3 :: N Int
ex4 :: E Int
ex1 = return 9
ex2 = return 9
ex3 = [1,2,3] >>= (\v -> return (v+1))
ex4 = (ErrorT [ok 1, ok 2, err]) >>= (\v -> return (v+1))
step :: E a -> R a
step x = Pause (x >>= (return . Done))
run :: R a -> E a
run (Pause phi) = phi >>= run
run (Done v) = return v
ex5 :: E Int
ex5 = run (step (ErrorT [ok 1, ok 2, err]))
mergeN :: N (N a) -> N a
mergeN = concat
mergeE :: N (E a) -> E a
mergeE = ErrorT . mergeN . map runErrorT
mergeR :: N (R a) -> R a
mergeR xs = Pause (mergeE (map return xs))
-- page 8 examples
ex6 :: N Int
ex6 = mergeN [[1,2],[4]]
ex7 :: E Int
ex7 = mergeE [ (ErrorT [ok 1, ok 2, err]), (ErrorT [ok 4,err])]
bindN :: [a] -> (a -> [b]) -> [b]
bindN = (>>=)
etaN :: a -> [a]
etaN = return
statusE :: E a -> E (Either Err a)
statusE phi = ErrorT $
(runErrorT phi) >>= \v ->
case v of
Right y -> return (Right (Right y))
Left Error -> return (Left Error)
statusR :: R a -> R (Either Err a)
statusR (Pause phi) =
Pause $ (statusE phi) >>= \v ->
case v of
Right x -> return (statusR x)
Left Error -> return (Done (Left Error))
statusR (Done v) = (Done (ok v))
throwE :: E a
throwE = ErrorT $ return (Left Error)
throwR :: R a
throwR = step throwE
fork :: R a -> R a
fork phi = mergeR [ phi, throwR ]
catchE :: E a -> E a -> E a
catchE phi gamma = (statusE phi) >>= \s ->
case s of
Right v -> return v
Left Error -> gamma
catchR :: R a -> R a -> R a
catchR phi gamma = (statusR phi) >>= \s ->
case s of
Right v -> return v
Left Error -> gamma
-- page 8 and 9 examples
ex8 :: E a
ex8 = throwE
ex9 :: E Int
ex9 = throwE >>= \v -> return (v + 1)
ex10 :: E (Either Err a)
ex10 = statusE throwE
ex11 :: E (Either Err Int)
ex11 = statusE (return 9)
ex12 :: E Int
ex12 = catchE throwE (return 9)
ex13 :: R Int
ex13 = fork (return 9)
ex14 :: E Int
ex14 = run (fork (return 9))
-- Section 4
data Expr = Val Int
| Add Expr Expr
| Seqn Expr Expr
| Throw
| Catch Expr Expr
| Block Expr
| Unblock Expr
deriving (Show)
evB :: Expr -> R Int
evB (Val i) = step (return i)
evB (Add e1 e2) = (evB e1) >>= \v1 ->
(evB e2) >>= \v2 ->
return (v1 + v2)
evB (Seqn e1 e2) = (evB e1) >> (evB e2)
evB Throw = throwR
evB (Catch e1 e2) = catchR (evB e1) (evB e2)
evB (Block e) = (evB e)
evB (Unblock e) = (evU e)
evU :: Expr -> R Int
evU (Val i) = fork (step (return i))
evU (Add e1 e2) = fork ((evU e1) >>= \v1 ->
(evU e2) >>= \v2 ->
return (v1 + v2))
evU (Seqn e1 e2) = fork ((evU e1) >> (evU e2))
evU Throw = fork throwR
evU (Catch e1 e2) = fork (catchR (evU e1) (evU e2))
evU (Block e) = fork (evB e)
evU (Unblock e) = fork (evU e)
ex15 :: E Int
ex15 = run (evU (Add (Val 1) (Val 2)))
Monday, January 4, 2010
kangaroo
Copperbox revision 1073.
I've reverted the changes made to ParseMonad in revision 1072, as the ByteString building parsers weren't useful.
Running the MIDI printer points to a persistent problem the intraparse parser - I'm not representing end-of-file in a useful way: the restrict combinator should be able to restrict to the the end-of-file and let the cursor go to the end-of-file (this is fine behaviour - it is only an error if an actually read is attempted at the end-of-file). Currently the restrict parser doesn't allow this and throws a range error if it tries to restrict to the end-of-file.
I've reverted the changes made to ParseMonad in revision 1072, as the ByteString building parsers weren't useful.
Running the MIDI printer points to a persistent problem the intraparse parser - I'm not representing end-of-file in a useful way: the restrict combinator should be able to restrict to the the end-of-file and let the cursor go to the end-of-file (this is fine behaviour - it is only an error if an actually read is attempted at the end-of-file). Currently the restrict parser doesn't allow this and throws a range error if it tries to restrict to the end-of-file.
kangaroo
Copperbox revision 1072.
A unsuccessful attempt to add parsers for extract long sequences of chars or word8's. Here I was using ByteStrings - but cons on ByteStrings is expensive, so the optimization (going to the end and parsing backwards so cons is natural) didn't really improve things.
I'll take out the changes to ParseMonad in the next commit.
A unsuccessful attempt to add parsers for extract long sequences of chars or word8's. Here I was using ByteStrings - but cons on ByteStrings is expensive, so the optimization (going to the end and parsing backwards so cons is natural) didn't really improve things.
I'll take out the changes to ParseMonad in the next commit.
Sunday, January 3, 2010
Hurdle and kangaroo
Copperbox revision 1071.
The stack printing now works in kangaroo. Hurdle's PECOFF parser seems to run again (it still has the problem with VC++ dlls), but the ar parser goes into an infinite loop.
** Update - the ar parser is just very slow - it uses [Char] in places where it shouldn't.
The stack printing now works in kangaroo. Hurdle's PECOFF parser seems to run again (it still has the problem with VC++ dlls), but the ar parser goes into an infinite loop.
** Update - the ar parser is just very slow - it uses [Char] in places where it shouldn't.
kangaroo
Copperbox revision 1069.
Small but valuable improvements to the ParseMonad code - I've added a new monadic control operator withSuccess. Maybe monads with error handling could do with some of the control operators from Control.Exception (but changed to work in the monad rather than IO of course).
Small but valuable improvements to the ParseMonad code - I've added a new monadic control operator withSuccess. Maybe monads with error handling could do with some of the control operators from Control.Exception (but changed to work in the monad rather than IO of course).
Saturday, January 2, 2010
kangaroo
Copperbox revision 1064.
I've added my own formatting library to Kangaroo to use instead of Text.PrettyPrint.HughesPJ.
Often I don't need the fitting behaviour of a proper printing library, so a couple of times I've half baked a simpler formatting library. With this one I'll attempt to make it a bit more than half baked.
Revision 1065 - adding another top-level import module - KangarooWriter.
I've added my own formatting library to Kangaroo to use instead of Text.PrettyPrint.HughesPJ.
Often I don't need the fitting behaviour of a proper printing library, so a couple of times I've half baked a simpler formatting library. With this one I'll attempt to make it a bit more than half baked.
Revision 1065 - adding another top-level import module - KangarooWriter.
Friday, January 1, 2010
kangaroo
Copperbox revision 1063.
I've changed to interface to intra-region parsers so the coda strategy is represented as an enumerated type rather than separate functions for each type (to do this is obvious in retrospect).
Unfortunately the MIDI parser has stopped working again, so I'm going to have to do some work on "debugging".
I've changed to interface to intra-region parsers so the coda strategy is represented as an enumerated type rather than separate functions for each type (to do this is obvious in retrospect).
Unfortunately the MIDI parser has stopped working again, so I'm going to have to do some work on "debugging".
Subscribe to:
Posts (Atom)
Blog Archive
-
▼
2010
(890)
-
▼
January
(48)
- Mullein M2
- KURE
- Mullein M2
- data-aviary
- arity-lib
- Mullein M2
- Hurdle and Kangaroo
- kangaroo
- kangaroo
- SFont - ZFont
- Hurdle, SFont and Kangaroo
- kangaroo
- kangaroo
- kangaroo
- kangaroo
- kangaroo
- kangaroo
- data-aviary
- data-aviary
- OpenVG binding
- OpenVG binding
- OpenVG binding
- OpenVG binding
- OpenVG binding
- precis
- precis
- precis
- precis
- precis
- precis
- zparse
- zparse
- zparse
- zparse
- zparse
- zparse
- zparse
- resumptions
- resumptions
- kangaroo
- kangaroo
- Hurdle and kangaroo
- kangaroo
- kangaroo
- kangaroo
- kangaroo
- kangaroo
- kangaroo
-
▼
January
(48)
About Me
- Stephen Tetley
- Disambiguating biog as there are a few Stephen Tetley's in the world. I'm neither a cage fighter or yachtsman. I studied Fine Art in the nineties (foundation Bradford 1992, degree Cheltenham 1992 - 95) then Computing part-time at Leeds Met graduating in 2003. I'm the Stephen Tetley on Haskell Cafe and Stackoverflow.