-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnci.hs
More file actions
99 lines (85 loc) · 2.14 KB
/
nci.hs
File metadata and controls
99 lines (85 loc) · 2.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import System.Environment
import System.IO
import qualified Data.ByteString as BS
data U = Fn (IO U -> IO U) | Pr (IO U) | MI Integer
data State = Code | Comment
liftU :: (IO U -> IO U) -> IO U
liftU f =
return $ Fn $ \x ->
f x
liftU2 :: (IO U -> IO U -> IO U) -> IO U
liftU2 f =
return $ Fn $ \x ->
return $ Fn $ \y ->
f x y
liftU3 :: (IO U -> IO U -> IO U -> IO U) -> IO U
liftU3 f =
return $ Fn $ \x ->
return $ Fn $ \y ->
return $ Fn $ \z ->
f x y z
($$) :: IO U -> IO U -> IO U
($$) f x = do
Fn f' <- f
f' x
s :: IO U
s = liftU3 $ \x y z -> (x $$ z) $$ (y $$ z)
k :: IO U
k = liftU2 $ \x _ -> x
castInt :: (Integral a, Integral b, Bounded b) => a -> b
castInt x
| x' >= toInteger (minBound `asTypeOf` to) &&
x' <= toInteger (maxBound `asTypeOf` to)
= to
| otherwise = undefined
where
x' = toInteger x
to = fromIntegral x
dec :: IO Integer -> IO U
dec mi = mi >>= flip go (k $$ (s $$ k $$ k))
where
go 0 n = n
go mi n = go (mi - 1) $ (s $$ (s $$ (k $$ s) $$ k)) $$ n
enc :: IO U -> IO Integer
enc n = do
MI mi <- n $$ suc $$ zero
return mi
where
suc = liftU $ \mi -> do
MI mi' <- mi
return $ MI $ mi' + 1
zero = return $ MI 0
get :: IO Integer
get = do
eof <- isEOF
if eof
then return 256
else toInteger . BS.head <$> BS.hGet stdin 1
put :: IO Integer -> IO ()
put n = n >>= BS.hPut stdout . BS.pack . (:[]) . castInt
interpret :: Handle -> State -> IO U
interpret h st@Code = hGetChar h >>= \c -> case c of
'`' -> do
f <- interpret h st
x <- interpret h st
(return f) $$ (return x)
'*' -> s
'/' -> k
'|' -> liftU2 $ \p f -> do
Pr p' <- p
x <- p'
f $$ (return x)
'_' -> liftU $ \x -> return $ Pr x
',' -> liftU $ \_ -> return $ Pr $ dec get
'.' -> liftU $ \n -> return $ Pr $ put (enc n) >> (s $$ k $$ k)
'#' -> interpret h Comment
_ -> interpret h st
interpret h st@Comment = hGetChar h >>= \c -> case c of
'\n' -> interpret h Code
_ -> interpret h st
main :: IO ()
main = do
hSetBuffering stdout NoBuffering
args <- getArgs
withFile (head args) ReadMode $ \h ->
interpret h Code >>= \(Pr p) -> p >> return ()