module Converter (rationalToGray, grayToSignIO, signToGray, Gray, startF, startC) where import Stream import Data.Ratio import Control.Concurrent import Control.Concurrent.MVar import System.IO.Unsafe type Gray = [Integer] type State = (Integer, Integer) -- Convert a rational number (in (-1,1)) to its Gray representation rationalToGray :: Rational -> Gray rationalToGray x |x<0 = f (negate' (rationalToStream (-x))) (0,0) |otherwise = f (rationalToStream x) (0,0) -- Function to implement the two heads Turing machine that convert a -- signed-digit stream to the corresponding Gray-code representation f :: Stream -> State -> Stream f (x:xs) (0,0) |x==(-1) = 0:f xs (0,0) |x==0 = c:1:ds |x==1 = 1:f xs (1,0) where c:ds = f xs (0,1) f (x:xs) (0,1) |x==(-1) = 0:f xs (1,0) |x==0 = c:0:ds |x==1 = 1:f xs (0,0) where c:ds = f xs (0,1) f (x:xs) (1,0) |x==(-1) = 1:f xs (0,0) |x==0 = c:1:ds |x==1 = 0:f xs (1,0) where c:ds = f xs (1,1) f (x:xs) (1,1) |x==(-1) = 1:f xs (1,0) |x==0 = c:0:ds |x==1 = 0:f xs (0,0) where c:ds = f xs (1,1) -- Anotherway to convert from a rational to Gray code representation -- Behave exactly the same like above rationalToGray' :: Rational -> Gray rationalToGray' x |x<0 = signToGray (negate' (rationalToStream (-x))) |otherwise = signToGray (rationalToStream x) -- Function to convert a signed-digit stream to Gray representation -- Is much shorter than above signToGray :: Stream -> Stream signToGray (1:xs) = 1:f'(signToGray xs) signToGray ((-1):xs) = 0:signToGray xs signToGray (0:xs) = c:1:(f' ds) where c:ds = signToGray xs -- Convert a Gray-code stream to the corresponding signed-digit representation -- Make use of threads grayToSignIO :: Stream -> IO Stream grayToSignIO (x1:x2:xs) = do c <- threadTesting(x1:x2:xs) if (c==1) then (do co <- unsafeInterleaveIO (grayToSignIO (f'(x2:xs))) return (1:co)) else if (c==2) then (do co <- unsafeInterleaveIO (grayToSignIO (x2:xs)) return ((-1):co)) else (do co <- unsafeInterleaveIO (grayToSignIO (x1:f' xs)) return (0:co)) -- Flip the first bit of an infinite stream f' (x:xs) = (f'' x):xs where f'' 1 = 0 f'' 0 = 1 -- Launch two threads which run concurrently, test for the first digit of the stream (1, 0 or bottom) -- As soon as one thread terminate, grab that result and proceed threadTesting :: Stream -> IO Int threadTesting xs = do m <- newEmptyMVar c1 <- forkIO (f1 m xs) c2 <- forkIO (f2 m xs) c <- takeMVar m killThread c1 killThread c2 return c -- Test case 1, when the first bit is either 1 or 0. -- In case of bottom, f1 will never terminate, then f2 will definitely terminate f1 :: MVar Int -> Stream -> IO() f1 m (0:xs) = putMVar m 2 f1 m (1:xs) = putMVar m 1 -- Test case 2, when the first bit is completely ignored, esp in case it was a bottom -- If the second bit is 1, then we can output, don't care value of the first bit -- If the second bit is 0, then loop forever, give chances to f1 to terminate f2 :: MVar Int -> Stream -> IO() f2 m (c1:c2:xs) |c2==1 = putMVar m 3 |otherwise = yield -- Testing startC :: IO() startC = do c<- unsafeInterleaveIO (grayToSignIO (1:1:z0)) putStrLn (show (take 100 c)) startF = signToGray ((-1):1:z0) z0 = 0:z0 loop' = loop' z1' = (1:z1')