Execute SNUSP/Haskell: Difference between revisions
m
Fixed syntax highlighting.
m (moved RCSNUSP/Haskell to Execute SNUSP/Haskell) |
m (Fixed syntax highlighting.) |
||
Line 15:
The Haskell code starts with lots of imports:
<
import System.IO
import System.Random
Line 26:
import Data.Array
import qualified Data.HashTable as H</
Use a list as an index into an array:
<
instance Ix a => Ix [a] where
Line 40:
inRange ([],[]) [] = True
inRange (l:ls, u:us) (i:is) = inRange (l,u) i && inRange (ls,us) is
rangeSize (ls,us) = product $ map rangeSize $ zip ls us</
or into an hashtable (the hash function could probably be improved):
<
cmpList [] [] = True
cmpList (x:xs) [] = x == 0 && cmpList xs []
Line 54:
combine :: Int -> Int -> Int
combine x 0 = x
combine x y = z * (z+1) `div` 2 + x where z = x + y</
Here it's important that index lists with trailing zeroes are treated just like this list without the zeroes, so we can handle any number of dimensions. We want the same flexibility when adding index lists:
<
[] <+> ys = ys
xs <+> [] = xs
(x:xs) <+> (y:ys) = (x+y) : (xs <+> ys)</
Some helper functions:
<
modify d t f = do
Line 86:
toChar = chr . fromInteger
fromChar = toInteger . ord</
Now, the commands. Given a thread, return a list of threads valid after one simulation step. In that way, ''exec'' can handle forks and thread termination on errors.
<
exec '+' d t = modify d t (+1)
Line 118:
-- NOOP
exec _ d t = return [t]</
The scheduler manages a list ''ts'' of active threads, and a list ''ks'' of threads waiting for input. If there are no more threads in either list, stop. If input is available, one blocked thread is executed. If no input is available and all threads are blocked, we block the interpreter, too (so the OS can do something else). Otherwise, try to execute one of the unblocked threads, first checking if it's still inside the code array.
<
run c d = schedule [thread] [] False where
Line 136:
| x == ',' = return ([],[t])
| otherwise = exec' x d t
where x = c ! (ip t)</
Finally, routines to run code from a string or a file, and the main program.
<
d <- H.new cmpList hashList
let x = length s `div` y
Line 158:
hSetBuffering stdin NoBuffering
[s] <- getArgs
runFile s</
==
To demonstrate the ease of introducing even more dimensions, let's implement commands ( and ) to move the data pointer along the z-axis, and a command ^ to rotate the IP direction around the (1,1,1) axis (i.e., left becomes up, up becomes "farther" on the z-axis, "farther" becomes left, etc.).
<
exec ')' d t = moveMp d t [0,0, 1]
exec '^' d t = return [t {dir=(d3:d1:d2:ds)}] where d1:d2:d3:ds = dir t <+> [0,0,0]</
|