packages feed

brainfuck-monad 0.1.0 → 0.2.0

raw patch · 2 files changed

+182/−70 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Control.Monad.BrainFuck: Constants :: NumConstants -> Integer -> Constants
- Control.Monad.BrainFuck: brainfuckConstants :: NumConstants -> (Constants -> BrainFuck a) -> String
- Control.Monad.BrainFuck: char :: Char -> BrainFuck ()
- Control.Monad.BrainFuck: data Constants
- Control.Monad.BrainFuck: loop :: Constants -> BrainFuck () -> BrainFuck ()
- Control.Monad.BrainFuck: pointAt :: Constants -> Integer -> BrainFuck ()
- Control.Monad.BrainFuck: type NumConstants = Int
- Control.Monad.BrainFuck: unchar :: Char -> BrainFuck ()
+ Control.Monad.BrainFuck: alloc :: BrainFuck a -> BrainFuck a
+ Control.Monad.BrainFuck: display :: String -> BrainFuck ()
+ Control.Monad.BrainFuck: helloworld' :: String
+ Control.Monad.BrainFuck: loopFrom :: Int -> (DataPointer -> BrainFuck ()) -> BrainFuck ()
+ Control.Monad.BrainFuck: mult :: Int -> BrainFuck ()
+ Control.Monad.BrainFuck: optimize :: String -> String
+ Control.Monad.BrainFuck: set :: Int -> BrainFuck ()
+ Control.Monad.BrainFuck: sum :: BrainFuck ()
+ Control.Monad.BrainFuck: unless0 :: BrainFuck () -> BrainFuck ()
+ Control.Monad.BrainFuck: zero :: BrainFuck ()
- Control.Monad.BrainFuck: forever :: Constants -> BrainFuck () -> BrainFuck ()
+ Control.Monad.BrainFuck: forever :: BrainFuck a -> BrainFuck ()
- Control.Monad.BrainFuck: loopUnless0 :: BrainFuck () -> BrainFuck ()
+ Control.Monad.BrainFuck: loopUnless0 :: BrainFuck a -> BrainFuck a

Files

Control/Monad/BrainFuck.hs view
@@ -35,15 +35,11 @@ output = opcode '.' -- | input byte, storing at data pointer input = opcode ','--- | if byte at data pointer is zero, jump to command after close+-- | if byte at data pointer is zero, jump to opcode after close open = opcode '['--- | if byte at data pointer is nonzero, jump to command after matching open+-- | if byte at data pointer is nonzero, jump to optoce after matching open close = opcode ']' -add, sub :: Int -> BrainFuck ()-add = multi incr-sub = multi decr- -- | Adds an arbitrary character to the program. -- Should not be used directly. opcode :: Char -> BrainFuck ()@@ -55,27 +51,15 @@ opcode' :: (DataPointer -> DataPointer) -> Char -> BrainFuck () opcode' f x =  BrainFuck $ \loc -> ([x], f loc, ()) --- | Run an action multiple times.-multi :: BrainFuck () -> Int -> BrainFuck ()-multi c n = do-	_ <- sequence (replicate n c)-	return ()---- | Assuming that the data pointer points to a 0, changes--- it to the value of a Char.-char :: Char.Char -> BrainFuck ()-char = multi incr . Char.ord---- | Undoes `char`-unchar :: Char.Char -> BrainFuck ()-unchar = multi decr . Char.ord---- | Runs an action with the data pointer pointing at a Char.-withChar :: Char.Char -> BrainFuck a -> BrainFuck a-withChar c a = do-	char c+-- | The loop is only run if the data pointer doesn't point to 0.+--+-- On entry, the loop body is run, and then it loops, until the data+-- pointer points to 0.+loopUnless0 :: BrainFuck a -> BrainFuck a+loopUnless0 a = do+	open 	r <- a-	unchar c+	close 	return r  -- | Gets the current address of the data pointer.@@ -92,64 +76,192 @@ 			then next >> setAddr n 			else return () --- | The loop is only run if the data pointer doesn't point to 0.------ On entry, the loop body is run, and then it loops, until the data--- pointer points to 0.-loopUnless0 :: BrainFuck () -> BrainFuck ()-loopUnless0 a = do-	open-	a-	close+-- | Run an action multiple times.+multi :: BrainFuck () -> Int -> BrainFuck ()+multi c n = do+	_ <- sequence (replicate n c)+	return () -data Constants = Constants NumConstants Integer+add, sub :: Int -> BrainFuck ()+-- adds an Int to the byte at the data pointer+add = multi incr+-- subtracts an Int from the byte at the data pointer+sub = multi decr -type NumConstants = Int+-- | Zeros the current data cell.+zero :: BrainFuck ()+zero = loopUnless0 decr --- | Let's run programs with data addresses 0..n reserved to always contain--- the numbers n..0+-- | Changes the current data cell to contain a specific value.+-- (It can start at any value).+set :: Int -> BrainFuck ()+set n = do+	zero+	add n	++-- | For higher-level programming in brainfuck, it's useful to have a way+-- to run a function, while allocating a memory cell, which is initialized+-- to contain 0. ----- These constants will make brainfuck quite a bit easier to use!-brainfuckConstants :: NumConstants -> (Constants -> BrainFuck a) -> String-brainfuckConstants numconstants a = brainfuck $ do-	M.forM_ [0..numconstants] $ \n -> do-		add (numconstants - n)-		next-	a (Constants numconstants 0)+-- This and many of the functions below assume that+-- cells to the left are in use, while cells to the right+-- are unused and may contain any data. Higher-level functions should+-- generally avoid changing the current cell, and should instead alloc+-- a new one to use.+alloc :: BrainFuck a -> BrainFuck a+alloc a = do+	next+	zero+	cell <- addr+	r <- a+	setAddr cell+	prev+	return r --- | Sets data pointer to point to one of the Constants.-pointAt :: Constants -> Integer -> BrainFuck ()-pointAt (Constants numconstants c) i = setAddr (c + fromIntegral numconstants - i)+-- | Allocates a new memory cell, populates it with a Char, and runs+-- the action.+withChar :: Char.Char -> BrainFuck a -> BrainFuck a+withChar c a = alloc $ do+	set (Char.ord c)+	a --- | Run an action in a loop, until the data pointer points to 0.-loop :: Constants -> BrainFuck () -> BrainFuck ()-loop constants a = do-	here <- addr-	pointAt constants 1+-- | Allocates a cell and uses it as the loop counter, starting from +-- the provided value. The action will continue running in a loop until+-- it decrements the counter to 0.+loopFrom :: Int -> (DataPointer -> BrainFuck ()) -> BrainFuck ()+loopFrom n a = alloc $ do+	i <- addr+	add n 	loopUnless0 $ do-		setAddr here+		a i+		setAddr i++-- | Runs an action in an infinite loop. The action should avoid+-- touching the current memory cell.+forever :: BrainFuck a -> BrainFuck ()+forever a = loopFrom 1 $ \_ -> do+	_ <- a+	return ()++-- | Runs the action unless the data pointer points to 0.+unless0 :: BrainFuck () -> BrainFuck ()+unless0 a = do+	start <- addr+	loopUnless0 $ do 		a+		next+		zero+	prev --- | Runs an action in an infinite loop.-forever :: Constants -> BrainFuck () -> BrainFuck ()-forever constants a = loop constants $ do-	a-	pointAt constants 1+-- | Adds the current and next data cells. The next cell is zeroed+-- and the sum is left in the current cell.+sum :: BrainFuck ()+sum = do+	next+	loopUnless0 $ do+		prev+		incr+		next+		decr+	prev --- | Prints out the ASCII characters, starting with space, repeatedly.--- --- TODO: Only print printable characters.+-- | Multiplies the current data cell by some value. Uses and zeros some+-- of the following cells.+mult :: Int -> BrainFuck ()+mult y = do+	x <- addr+	alloc $ do+		c1 <- addr++		-- Copy x to c1, and zero x.+		setAddr x+		loopUnless0 $ do+			setAddr c1+			incr+			setAddr x+			decr+	+		setAddr c1+		loopUnless0 $ do+			loopFrom y $ \c2 -> do+				decr+				setAddr x+				incr+			setAddr c1+			decr++-- | Displays a string. Tries to generate a fairly small brainfuck program,+-- using a few encoding tricks. The current cell is modified, and not+-- cleaned up at the end, so run using alloc if necessary.+display :: String -> BrainFuck ()+display s = start >>= go True (map Char.ord s)+  where+	-- Get to letter 104 ('a' is 97) quickly by multiplication.+	start = do+		zero+		x <- addr+		add 13+		mult 8+		return (13 * 8)+	+	go _ [] _ = return ()+	go started (c:cs) n+		| not started && delta > 13 = start >>= go True (c:cs)+		| otherwise = do+			if abs delta < c+				then multi (if delta > 0 then incr else decr) (abs delta)+				else set c+			output+			go False cs c+	  where+		delta = c - n++-- | Prints out the alphabet, repeatedly. demo :: String-demo = brainfuckConstants 1 $ \constants -> do-	add $ Char.ord ' '-	forever constants $ do-		add 1-		output+demo = brainfuck $ forever $ do+	alloc $ do+		c <- addr+		set start+		+		loopFrom numchars $ \i -> do+			decr+			setAddr c+			output+			incr+		withChar ' ' output+  where+	start = Char.ord 'a'+	end = Char.ord 'z'+	numchars = end - start + 1 +-- | Copy input to output. cat :: String-cat = brainfuckConstants 1 $ flip forever $ input >> output+cat = brainfuck $ forever $ input >> output +-- | Simple hello world. helloworld :: String helloworld = brainfuck $ 	M.forM_ "hello, world!" $ 		flip withChar output++-- | Optimized to use less space.+helloworld' :: String+helloworld' = optimize $ brainfuck $ display "hello, world!"++-- | Simple optimiser for brainfuck code.+optimize :: String -> String+optimize s = go s [] s+  where+	go orig r [] =+		let new = reverse r in+		if new /= orig+			then go new [] new+			else new+	go orig r ('>':'<':l) = go orig r l -- <> is a noop+	go orig r ('<':'>':l) = go orig r l -- >< is a noop+	go orig r ('+':'-':l) = go orig r l -- +- is a noop+	go orig r ('-':'+':l) = go orig r l -- -+ is a noop+	go orig r ('[':']':l) = go orig r l -- [] is a noop+	go orig [] ('[':'-':']':l) = go orig [] l -- [-] at start is noop+	go orig [] ('>':'[':'-':']':l) = go orig [] l -- >[-] at start is noop+	go orig r (c:l) = go orig (c:r) l
brainfuck-monad.cabal view
@@ -1,5 +1,5 @@ Name: brainfuck-monad-Version: 0.1.0+Version: 0.2.0 Cabal-Version: >= 1.8 License: BSD3 Maintainer: Joey Hess <id@joeyh.name>