c4ec206590d25d581b9a96f242c22936d8d0b2e9903331ce50b30ad7de254bd6.tri (7237B)
1 !import base * 2 !export * 3 4 -- IO constructors for host-interpreted interaction trees. 5 -- Free-monad style: Bind is the single sequencing mechanism. 6 7 version = 1 8 9 io = action : pair "tricuIO" (pair version action) 10 11 pure = x : pair 0 x 12 bind = action k : pair 1 (pair action k) 13 -- Terminal diagnostic control for the Haskell IO scheduler. 14 abortIO = diagnostic : pair 2 diagnostic 15 16 putStr = s : pair 10 s 17 getLine = pair 11 t 18 19 -- Source boundary only: Result (raw octets, Unicode scalar list), strict UTF-8. 20 -- Initial BOM is rejected; binary readFile remains unchanged. 21 readSourceFile = p : pair 37 p 22 encodeSourceText = chars : pair 38 chars 23 24 readFile = p : pair 20 p 25 writeFile = p c : pair 21 (pair p c) 26 putBytes = bs : pair 12 bs 27 writeBytes = p c : pair 22 (pair p c) 28 29 listDirectory = p : pair 23 p 30 renameFile = old new : pair 24 (pair old new) 31 createDirectory = p : pair 25 p 32 deleteFile = p : pair 26 p 33 fileExists = p : pair 27 p 34 35 sha256Hex = bs : pair 28 bs 36 currentTime = pair 29 t 37 -- Filesystem-only atomic primitives. writeBytesIfAbsent returns ok true 38 -- for a new object and ok false if the path already exists, without changing 39 -- it. atomicWriteBytes returns ok true after atomic replacement of an alias. 40 -- Hosts sync file contents before publication and the parent directory 41 -- afterwards. Publish referenced objects before replacing a lock or alias; 42 -- a post-publication sync failure can leave the new name visible. 43 writeBytesIfAbsent = p bs : pair 32 (pair p bs) 44 atomicWriteBytes = p bs : pair 33 (pair p bs) 45 46 -- Read-permitted canonical tree-term transport. Verify the fixed 47 -- arboricx.tree-term.v1 digest before decoding; returns Result tree. 48 -- This loads an inert normal-form tree, never source or an applied program. 49 readTreeTerm = p digest : pair 34 (pair p digest) 50 51 -- Fixed canonical tree-term domain. No byte-list marshalling. Publication 52 -- requires read and write permission, never replaces an existing path, and 53 -- verifies its bytes even when another publisher wins. Directories are explicit. 54 hashTreeTerm = tree : pair 35 tree 55 writeTreeTermIfAbsent = p digest tree : pair 36 (pair p (pair digest tree)) 56 57 -- Name-neutral indexed DAG transport under arboricx.indexed-tree.v1. 58 -- These primitive codecs preserve sharing; tricu chooses paths and publication 59 -- order. Read verifies before decode; write verifies an existing/racing winner. 60 -- Both read and write permission are required for no-replace publication. 61 readIndexedTree = p digest : pair 50 (pair p digest) 62 hashIndexedTree = tree : pair 51 tree 63 writeIndexedTreeIfAbsent = p digest tree : pair 52 (pair p (pair digest tree)) 64 65 ask = pair 30 t 66 local = f action : pair 31 (pair f action) 67 68 get = pair 40 t 69 put = s : pair 41 s 70 71 fork = action : pair 60 action 72 await = handle : pair 61 handle 73 yield = pair 62 t 74 sleep = ms : pair 63 ms 75 76 -- --------------------------------------------------------------------------- 77 -- Generic sequencing combinators 78 -- --------------------------------------------------------------------------- 79 80 thenIO = a b : bind a (_ : b) 81 mapIO = action f : bind action (x : pure (f x)) 82 void = action : bind action (_ : pure t) 83 84 -- --------------------------------------------------------------------------- 85 -- Conditional execution 86 -- --------------------------------------------------------------------------- 87 88 when = cond action : matchBool action (pure t) cond 89 unless = cond action : matchBool (pure t) action cond 90 91 -- --------------------------------------------------------------------------- 92 -- Infinite loop 93 -- --------------------------------------------------------------------------- 94 95 forever action = bind action (_ : forever action) 96 97 -- --------------------------------------------------------------------------- 98 -- Result-aware combinators 99 -- --------------------------------------------------------------------------- 100 101 -- Propagate driver Result on error; run okCase on success. 102 onOk action okCase = (do bind 103 reply <- action 104 matchResult (_ _ : pure reply) okCase reply) 105 106 -- Value-only adapter: success remainder is explicitly discarded. 107 onOk_ action okCase = onOk action (value _ : okCase value) 108 109 onResult action errCase okCase = (do bind 110 reply <- action 111 matchResult errCase okCase reply) 112 113 -- Value-only handlers explicitly discard both Result remainders. 114 onResult_ action errCase okCase = (onResult action 115 (message _ : errCase message) 116 (value _ : okCase value)) 117 118 mapErrIO prefix action = 119 onResult_ action 120 (e : pure (err (append prefix e) t)) 121 (v : pure (ok v t)) 122 123 -- --------------------------------------------------------------------------- 124 -- Convenience helpers 125 -- --------------------------------------------------------------------------- 126 127 print = s : void (putStr s) 128 putStrLn = s : void (putStr (append s "\n")) 129 130 -- --------------------------------------------------------------------------- 131 -- Result-aware file helpers 132 -- --------------------------------------------------------------------------- 133 134 onReadFile = path : onResult (readFile path) 135 136 onWriteFile = path contents : onResult (writeFile path contents) 137 138 onListDirectory = path : onResult (listDirectory path) 139 onRenameFile = old new : onResult (renameFile old new) 140 onCreateDirectory = path : onResult (createDirectory path) 141 onDeleteFile = path : onResult (deleteFile path) 142 onFileExists = path : onResult (fileExists path) 143 onSha256Hex = bs : onResult (sha256Hex bs) 144 onCurrentTime = onResult currentTime 145 146 -- --------------------------------------------------------------------------- 147 -- Convenience helpers for the common cases 148 -- --------------------------------------------------------------------------- 149 150 readFileOrPrintError = (path okCase : 151 onReadFile path 152 (err rest : putStrLn (append "Read failed: " err)) 153 okCase) 154 155 writeFileOrPrintError = (path contents okCase : 156 onWriteFile path contents 157 (err rest : putStrLn (append "Write failed: " err)) 158 okCase) 159 160 copyFile = (src dst : 161 onResult (readFile src) 162 (err rest : putStrLn (append "Read failed: " err)) 163 (contents rest : 164 onResult (writeFile dst contents) 165 (err rest : putStrLn (append "Write failed: " err)) 166 (_ _ : pure t))) 167 168 -- --------------------------------------------------------------------------- 169 -- Ordinary-completion cleanup (not exception masking or abort recovery) 170 -- --------------------------------------------------------------------------- 171 172 -- Run cleanup once after action returns any ordinary value/Result, including 173 -- failure; ignore cleanup's ordinary result and preserve the action's result. 174 -- Terminal abortIO, divergence and host exceptions can prevent cleanup. 175 finally action cleanup = (do bind 176 result <- action 177 cleanup 178 pure result) 179 180 -- Acquisition returns a Result. Failure propagates unchanged without use or 181 -- release; success supplies the resource value (not the Result envelope). 182 -- Use the same ordinary-completion/cleanup-result policy as finally. 183 bracket acquire release use = (onOk_ acquire 184 (resource : finally (use resource) (release resource)))