[clean-list] Combine two library versions in one executable?

Tomasz Zielonka tomasz.zielonka at gmail.com
Tue Feb 22 12:07:49 MET 2005


On Tue, Feb 22, 2005 at 11:00:50AM +0100, Erik Zuurbier wrote:
> Dear Cleaners,
> 
> I have a libray version that I consider semantically correct (actually it
> is a parser combinator library), but it is not optimally efficient.
> 
> And then I have a second version that exports exactly the same functions
> and types. This version is faster but considerably more complicated. But
> is it semantically correct?
> 
> I would like to test that by running a number of actual parsers, each compiled
> twice - with both library versions. Then I would like to compare the results
> and list the differences. Call it model checking if you like.
> 
> In Clean I see the following options:
> [...]

4) Introduce a third parser type with combinators that build both types
   of parsers. I managed to do something like this in Haskell for two
   libraries of monadic parser combinators - see the attached example.

   Usage example:

    tomek at green:~/lang/haskell/bimonad$ ghci-6.4.20050220
       ___         ___ _
      / _ \ /\  /\/ __(_)
     / /_\// /_/ / /  | |      GHC Interactive, version 6.4.20050220, for Haskell 98.
    / /_\\/ __  / /___| |      http://www.haskell.org/ghc/
    \____/\/ /_/\____/|_|      Type :? for help.

    Loading package base-1.0 ... linking ... done.
    Prelude> :l Bi
    Compiling Bi               ( Bi.hs, interpreted )
    Ok, modules loaded: Bi.

    *Bi> ReadPrec.readPrec_to_S (fst $ runBi $ test) 0 "123,456,7890"
    [(["123","456","7890"],"")]

    *Bi> Parsec.parse (snd $ runBi $ test) "?" "123,456,7890"
    Right ["123","456","7890"]

Best regards
Tomasz
-------------- next part --------------

module Bi where

import Control.Monad.Writer
import qualified Text.ParserCombinators.Parsec as Parsec
import qualified Text.Read as ReadPrec
import Text.ParserCombinators.Parsec (GenParser)
import Text.Read (ReadPrec)
import Char (isDigit)

newtype Bi m1 m2 a = Bi { runBi :: (m1 a, m2 a) }

instance (Monad m1, Monad m2) => Monad (Bi m1 m2) where
    return x = Bi (return x, return x)
    Bi (m1, m2) >>= f =
        Bi ( m1 >>= (fst . runBi . f), m2 >>= (snd . runBi . f) )

get :: Bi ReadPrec (GenParser Char ()) Char
get = Bi (ReadPrec.get, Parsec.anyChar)

choice :: [Bi ReadPrec (GenParser Char ()) a] -> Bi ReadPrec (GenParser Char ()) a
choice chs = Bi (ReadPrec.choice (map (fst . runBi) chs), Parsec.choice (map (snd . runBi) chs))

pfail :: Bi ReadPrec (GenParser Char ()) a
pfail = Bi (ReadPrec.pfail, Parsec.pzero)

try :: Bi ReadPrec (GenParser Char ()) a -> Bi ReadPrec (GenParser Char ()) a
try (Bi (f, s)) = Bi (f, Parsec.try s)

eof :: Bi ReadPrec (GenParser Char ()) ()
eof = Bi ((ReadPrec.look >>= \cs -> when (not (null cs)) ReadPrec.pfail), Parsec.eof)

test = do
    l <- number `sepBy1` char ','
    eof
    return l
  where
    digit = try $ do
        c <- get
        when (not (isDigit c)) pfail
        return c

    number = many1 digit

    char c = try $ do
        c' <- get
        when (c /= c') pfail
        return c

    sepBy1 p sep = do
        x <- p
        choice
            [ do
                sep
                xs <- sepBy p sep
                return (x : xs)
            , return [x]
            ]

    sepBy p sep = do
        choice
            [ do
                x <- p
                choice
                    [ do
                        sep
                        xs <- sepBy p sep
                        return (x : xs)
                    , do
                        return [x]
                    ]
            , return []
            ]

    many1 p = do
        x <- p
        xs <- many p
        return (x : xs)

    many p = do
        choice
            [ do
                x <- p
                xs <- many p
                return (x : xs)
            , do
                return []
            ]



More information about the clean-list mailing list