packages feed

copilot-2.0.7: Examples/Languages.hs

-- | Examples of parsing various languages.  We'll assume input tokens come from
-- an external variable.  Assume the input doesn't given tokens outside the
-- alphabet, and the result is always delayed by one w.r.t. the input stream.

-- Copilot can compute at least NP-Complete problems.

{-# LANGUAGE RebindableSyntax #-}

module Languages (languages) where

import Language.Copilot
import qualified Prelude as P
import qualified Data.List as L

---------------------------------------------------------------------------------
-- Regular expressions

{- 
We'll build a Copilot program to accept the regular language over the alphabet
{0,1} that contains an even number of 0s.  
-}

reAccept :: Spec
reAccept = do 
  observer "accept" accept
  observer "string" string
  where
  accept :: Stream Bool
  accept = [True] ++ if string == 0
                       then if accept then false
                              else true
                       else accept

  -- Input tokens.
  string :: Stream Word8
  string = [0] ++ if string == 0 then 1 else 0

-- interpret 10 reAccept

---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
-- Context-free Grammars

{-
This Copilot program recognizes <0^n 1^n>, for n >= 0.  
-}

cfAccept :: Int -> Spec
cfAccept n = do
  observer "accept" accept
  observer "string" string
  where
  accept :: Stream Bool
  accept = if zerosSeen == 0 
             then true
             else false

  zerosSeen :: Stream Word64
  zerosSeen = [0] ++ if string == 0 
                       then zerosSeen + 1
                       else zerosSeen - 1

  -- Input tokens.
  string :: Stream Word8
  string = L.replicate n 0 P.++ L.replicate n 1 ++ 0 -- don't care about part of
                                                     -- stream after ++

-- interpret 40 (cfAccept 10)
---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
-- Context-sensitive grammars

{-
This Copilot program recognizes <0^n 1^n 2^n>, for n >= 0.  
-}

csAccept :: Int -> Spec
csAccept n = do
  observer "accept" accept
  observer "string" string
  where
  accept :: Stream Bool
  accept = if zerosSeen == 0 && onesSeen == 0
             then true
             else false

  zerosSeen :: Stream Word64
  zerosSeen = [0] ++ if string == 0
                           then zerosSeen + 1
                           else if string == 1 
                                  then zerosSeen - 1
                                  else zerosSeen

  onesSeen :: Stream Word64
  onesSeen = [0] ++ if string == 1
                      then onesSeen + 1
                      else if string == 0 
                             then onesSeen
                             else onesSeen - 1

  -- Input tokens.
  string :: Stream Word8
  string = L.replicate n 0 P.++ L.replicate n 1 P.++ L.replicate n 2 
             ++ 0 -- don't care about part of
                  -- stream after ++

-- interpret 40 (csAccept 5)
---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
-- Context-sensitive grammars

{-
This Copilot program recognizes the "copy language" <xx | x \in {0,1}*>.

Note: the "trick" is to encode the history of streams in a bitvector.  Thus, we
can only recognize arbitrarily long words if we have arbitrarily long
bitvectors.  There is nothing in Copilot preventing this, but the largest base
type is currently a Word64.  

Without this encoding, we couldn't build a recognizers, because we can't
generate new streams on the fly or look back arbitrarily far in the history of a
stream; both are fixed at compile time.

-}


copyAccept :: Spec
copyAccept = do
  observer "accept" accept
  observer "hist" hist
  observer "string" string
  observer "cnt" cnt
  where

  accept :: Stream Bool
  accept = if cnt `mod` 2 == 1 then false else bottom == top 
    where
    halfCnt  = cnt `div` 2
    zeroBot  = (complement $ (2^halfCnt) - 1) .&. hist
    top      = zeroBot .>>. halfCnt
    bottom   = hist - zeroBot

  hist :: Stream Word64
  hist = [0] ++ ((2^cnt) * cast string) + hist

  cnt :: Stream Word64
  cnt = [0] ++ cnt + 1

  -- Input tokens.
  string :: Stream Word8
  string = let x = [1,0,0,1,0,1] in 
           x P.++ x
             ++ 0 -- don't care about part of
                  -- stream after ++

---------------------------------------------------------------------------------

languages :: IO ()
languages = do
  interpret 20 reAccept 
  interpret 20 (cfAccept 10)
  interpret 20 (csAccept 10)
  interpret 20 copyAccept

---------------------------------------------------------------------------------
-- -- Recognize the language of arbitrarily long sequence of prime numbers.

-- -- Sieve of Eratosthenes
-- primes :: Word64 -> [Word64]
-- primes n = primes' 2 nums

--   where 
--   nums = [2..n] 

--   f :: Word64 -> [Word64] -> [Word64]
--   f x = L.filter (\a -> P.not (P.rem a x P.== 0 P.&& a P.> x))

--   primes' :: Word64 -> [Word64] -> [Word64]
--   primes' x ls = let ls' = f x ls in
--                  -- Can't use rebinded if-the-else syntax
--                  case ls' P.== ls of
--                    True  -> ls
--                    False -> primes' (x P.+ 1) ls'

-- primesInf :: [Word64]
-- primesInf = foldr primes' [2] [3..]

--   where 

--   -- returns divisors that evenly divide x
--   f :: Word64 -> [Word64] -> Bool
--   f x ls = ls `seq` (L.or $ map (\a -> P.rem x a P.== 0) ls)
--      -- L.filter (\a -> P.rem x a P.== 0)

--   primes' :: Word64 -> [Word64] -> [Word64]
--   primes' next prms = case prms `seq` f next prms of
--                         True  -> prms `seq` (next:prms)
--                         False -> prms



-- primesAccept :: Word64 -> Spec
-- primesAccept n = do
--   observer "primes" primesStrm
--   observer "accept" accept

--   where
--   -- Assume we are implementing a Sieve of Eratosthenes
--   accept :: Stream Word64
--   accept = 

--   primesStrm :: Stream Word64
--   primesStrm = primes n ++ 0 -- don't care about rest of values after ++