functionalscript 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/README.md +5 -3
  2. package/fjs/asn.1/module.f.mjs +8 -1
  3. package/fjs/asn.1/proof.f.d.mts +10 -0
  4. package/fjs/asn.1/proof.f.mjs +16 -0
  5. package/fjs/basen/base128/module.f.mjs +22 -5
  6. package/fjs/bnf/data/module.f.d.mts +32 -6
  7. package/fjs/bnf/data/module.f.mjs +112 -7
  8. package/fjs/bnf/data/proof.f.d.mts +2 -0
  9. package/fjs/bnf/data/proof.f.mjs +74 -3
  10. package/fjs/bnf/data/types.d.ts +20 -2
  11. package/fjs/bnf/descent/module.f.d.mts +28 -14
  12. package/fjs/bnf/descent/module.f.mjs +122 -77
  13. package/fjs/bnf/descent/proof.f.d.mts +2 -0
  14. package/fjs/bnf/descent/proof.f.mjs +117 -31
  15. package/fjs/bnf/descent/types.d.ts +12 -14
  16. package/fjs/bnf/ll1/module.f.d.mts +64 -22
  17. package/fjs/bnf/ll1/module.f.mjs +214 -154
  18. package/fjs/bnf/ll1/proof.f.d.mts +15 -2
  19. package/fjs/bnf/ll1/proof.f.mjs +323 -149
  20. package/fjs/bnf/ll1/types.d.ts +16 -24
  21. package/fjs/bnf/matcher/module.f.d.mts +66 -0
  22. package/fjs/bnf/matcher/module.f.mjs +81 -0
  23. package/fjs/bnf/matcher/proof.f.d.mts +10 -0
  24. package/fjs/bnf/matcher/proof.f.mjs +79 -0
  25. package/fjs/bnf/matcher/types.d.ts +54 -0
  26. package/fjs/bnf/testlib.f.d.mts +31 -0
  27. package/fjs/bnf/testlib.f.mjs +80 -0
  28. package/fjs/cas/cli/module.f.d.mts +1 -1
  29. package/fjs/cas/cli/module.f.mjs +14 -20
  30. package/fjs/cas/cli/proof.f.d.mts +1 -3
  31. package/fjs/cas/cli/proof.f.mjs +44 -33
  32. package/fjs/cas/evo/module.f.d.mts +64 -18
  33. package/fjs/cas/evo/module.f.mjs +148 -70
  34. package/fjs/cas/evo/proof.f.d.mts +10 -1
  35. package/fjs/cas/evo/proof.f.mjs +305 -223
  36. package/fjs/cas/evo/types.d.ts +45 -9
  37. package/fjs/cas/module.f.d.mts +18 -32
  38. package/fjs/cas/module.f.mjs +129 -128
  39. package/fjs/cas/proof.f.d.mts +11 -8
  40. package/fjs/cas/proof.f.mjs +259 -147
  41. package/fjs/cas/types.d.ts +24 -10
  42. package/fjs/ci/config/module.f.d.mts +2 -2
  43. package/fjs/ci/config/module.f.mjs +2 -2
  44. package/fjs/ci/module.f.d.mts +5 -5
  45. package/fjs/ci/module.f.mjs +8 -7
  46. package/fjs/ci/nix/module.f.d.mts +7 -5
  47. package/fjs/ci/nix/module.f.mjs +13 -12
  48. package/fjs/ci/nix/proof.f.mjs +2 -2
  49. package/fjs/ci/proof.f.mjs +9 -5
  50. package/fjs/cli/module.f.d.mts +4 -6
  51. package/fjs/cli/module.f.mjs +4 -8
  52. package/fjs/cli/proof.f.mjs +17 -16
  53. package/fjs/cli/types.d.ts +2 -3
  54. package/fjs/common/monoid/types.d.ts +1 -1
  55. package/fjs/crypto/hmac/module.f.mjs +2 -2
  56. package/fjs/crypto/sha2/module.f.mjs +3 -1
  57. package/fjs/crypto/sha2/proof.f.d.mts +1 -0
  58. package/fjs/crypto/sha2/proof.f.mjs +24 -0
  59. package/fjs/crypto/sha2/types.d.ts +11 -0
  60. package/fjs/crypto/sign/module.f.mjs +2 -2
  61. package/fjs/dev/module.f.d.mts +13 -4
  62. package/fjs/dev/module.f.mjs +56 -27
  63. package/fjs/dev/update/module.f.d.mts +9 -4
  64. package/fjs/dev/update/module.f.mjs +14 -10
  65. package/fjs/dev/update/proof.f.d.mts +1 -3
  66. package/fjs/dev/update/proof.f.mjs +10 -5
  67. package/fjs/djs/module.f.d.mts +13 -5
  68. package/fjs/djs/module.f.mjs +31 -16
  69. package/fjs/djs/parser/module.f.d.mts +13 -3
  70. package/fjs/djs/parser/module.f.mjs +117 -16
  71. package/fjs/djs/parser/proof.f.d.mts +5 -1
  72. package/fjs/djs/parser/proof.f.mjs +274 -12
  73. package/fjs/djs/parser/types.d.ts +7 -1
  74. package/fjs/djs/proof.f.d.mts +18 -2
  75. package/fjs/djs/proof.f.mjs +187 -12
  76. package/fjs/djs/serializer/module.f.d.mts +25 -8
  77. package/fjs/djs/serializer/module.f.mjs +61 -15
  78. package/fjs/djs/serializer/proof.f.d.mts +5 -0
  79. package/fjs/djs/serializer/proof.f.mjs +23 -1
  80. package/fjs/djs/tokenizer/module.f.d.mts +17 -5
  81. package/fjs/djs/tokenizer/module.f.mjs +99 -60
  82. package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
  83. package/fjs/djs/tokenizer/proof.f.mjs +74 -67
  84. package/fjs/djs/transpiler/module.f.d.mts +12 -7
  85. package/fjs/djs/transpiler/module.f.mjs +82 -56
  86. package/fjs/djs/transpiler/types.d.ts +7 -3
  87. package/fjs/djs/types.d.ts +7 -1
  88. package/fjs/effects/list/module.f.d.mts +14 -11
  89. package/fjs/effects/list/module.f.mjs +13 -11
  90. package/fjs/effects/list/types.d.ts +27 -7
  91. package/fjs/effects/memory/module.f.d.mts +2 -1
  92. package/fjs/effects/memory/module.f.mjs +3 -4
  93. package/fjs/effects/memory/proof.f.mjs +13 -7
  94. package/fjs/effects/memory/types.d.ts +4 -3
  95. package/fjs/effects/mock/module.f.d.mts +20 -4
  96. package/fjs/effects/mock/module.f.mjs +37 -5
  97. package/fjs/effects/mock/types.d.ts +10 -1
  98. package/fjs/effects/module.d.mts +4 -2
  99. package/fjs/effects/module.f.d.mts +466 -280
  100. package/fjs/effects/module.f.mjs +537 -299
  101. package/fjs/effects/module.mjs +2 -1
  102. package/fjs/effects/node/memory/module.d.mts +4 -2
  103. package/fjs/effects/node/memory/module.mjs +6 -3
  104. package/fjs/effects/node/memory/proof.mjs +10 -4
  105. package/fjs/effects/node/module.d.mts +4 -3
  106. package/fjs/effects/node/module.f.d.mts +168 -33
  107. package/fjs/effects/node/module.f.mjs +256 -52
  108. package/fjs/effects/node/module.mjs +57 -34
  109. package/fjs/effects/node/proof.f.d.mts +28 -2
  110. package/fjs/effects/node/proof.f.mjs +161 -42
  111. package/fjs/effects/node/types.d.ts +106 -18
  112. package/fjs/effects/node/virtual/module.f.d.mts +18 -4
  113. package/fjs/effects/node/virtual/module.f.mjs +110 -68
  114. package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
  115. package/fjs/effects/node/virtual/proof.f.mjs +190 -9
  116. package/fjs/effects/proof.f.d.mts +69 -37
  117. package/fjs/effects/proof.f.mjs +410 -130
  118. package/fjs/effects/types.d.ts +161 -33
  119. package/fjs/emergent_testing/module.f.d.mts +19 -12
  120. package/fjs/emergent_testing/module.f.mjs +93 -33
  121. package/fjs/emergent_testing/proof.f.d.mts +21 -7
  122. package/fjs/emergent_testing/proof.f.mjs +166 -32
  123. package/fjs/emergent_testing/types.d.ts +22 -4
  124. package/fjs/fsm/module.f.d.mts +14 -4
  125. package/fjs/fsm/module.f.mjs +54 -37
  126. package/fjs/fsm/proof.f.d.mts +2 -0
  127. package/fjs/fsm/proof.f.mjs +83 -114
  128. package/fjs/js/keywords/module.f.d.mts +52 -0
  129. package/fjs/js/keywords/module.f.mjs +72 -0
  130. package/fjs/js/keywords/proof.f.d.mts +3 -0
  131. package/fjs/js/keywords/proof.f.mjs +13 -0
  132. package/fjs/js/tokenizer/module.f.d.mts +26 -6
  133. package/fjs/js/tokenizer/module.f.mjs +145 -159
  134. package/fjs/js/tokenizer/proof.f.d.mts +1 -0
  135. package/fjs/js/tokenizer/proof.f.mjs +54 -24
  136. package/fjs/js/tokenizer/types.d.ts +33 -24
  137. package/fjs/mcp/cas/module.f.d.mts +1 -6
  138. package/fjs/mcp/cas/module.f.mjs +55 -51
  139. package/fjs/mcp/cas/proof.f.d.mts +15 -0
  140. package/fjs/mcp/cas/proof.f.mjs +174 -0
  141. package/fjs/mcp/evo/module.f.d.mts +19 -10
  142. package/fjs/mcp/evo/module.f.mjs +48 -27
  143. package/fjs/mcp/evo/proof.f.d.mts +6 -1
  144. package/fjs/mcp/evo/proof.f.mjs +115 -31
  145. package/fjs/mcp/module.f.d.mts +4 -4
  146. package/fjs/mcp/module.f.mjs +6 -6
  147. package/fjs/mcp/proof.f.d.mts +5 -3
  148. package/fjs/mcp/proof.f.mjs +112 -46
  149. package/fjs/media/html/module.f.mjs +1 -1
  150. package/fjs/media/json/extended/module.f.d.mts +82 -0
  151. package/fjs/media/json/extended/module.f.mjs +153 -0
  152. package/fjs/media/json/extended/proof.f.d.mts +42 -0
  153. package/fjs/media/json/extended/proof.f.mjs +127 -0
  154. package/fjs/media/json/extended/types.d.ts +23 -0
  155. package/fjs/media/json/module.f.d.mts +8 -2
  156. package/fjs/media/json/module.f.mjs +43 -41
  157. package/fjs/media/json/number/module.f.d.mts +59 -0
  158. package/fjs/media/json/number/module.f.mjs +136 -0
  159. package/fjs/media/json/number/proof.f.d.mts +24 -0
  160. package/fjs/media/json/number/proof.f.mjs +86 -0
  161. package/fjs/media/json/number/types.d.ts +28 -0
  162. package/fjs/media/json/parser/module.f.d.mts +25 -13
  163. package/fjs/media/json/parser/module.f.mjs +114 -70
  164. package/fjs/media/json/parser/proof.f.d.mts +5 -0
  165. package/fjs/media/json/parser/proof.f.mjs +31 -1
  166. package/fjs/media/json/parser/types.d.ts +33 -14
  167. package/fjs/media/json/rtti/module.f.d.mts +1 -1
  168. package/fjs/media/json/rtti/module.f.mjs +1 -1
  169. package/fjs/media/json/rtti/proof.f.mjs +9 -9
  170. package/fjs/media/json/schema/module.f.mjs +3 -13
  171. package/fjs/media/json/schema/proof.f.d.mts +0 -1
  172. package/fjs/media/json/schema/proof.f.mjs +1 -2
  173. package/fjs/media/json/serializer/module.f.d.mts +32 -1
  174. package/fjs/media/json/serializer/module.f.mjs +64 -2
  175. package/fjs/media/json/tokenizer/module.f.mjs +7 -3
  176. package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
  177. package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
  178. package/fjs/media/json/types.d.ts +36 -10
  179. package/fjs/media/lock/module.f.d.mts +100 -0
  180. package/fjs/media/lock/module.f.mjs +125 -0
  181. package/fjs/media/lock/proof.f.d.mts +33 -0
  182. package/fjs/media/lock/proof.f.mjs +196 -0
  183. package/fjs/media/lock/types.d.ts +15 -0
  184. package/fjs/media/module.f.d.mts +6 -5
  185. package/fjs/media/module.f.mjs +8 -7
  186. package/fjs/media/note/module.f.d.mts +121 -0
  187. package/fjs/media/note/module.f.mjs +131 -0
  188. package/fjs/media/note/proof.f.d.mts +29 -0
  189. package/fjs/media/note/proof.f.mjs +150 -0
  190. package/fjs/media/note/types.d.ts +10 -0
  191. package/fjs/media/proof.f.d.mts +4 -1
  192. package/fjs/media/proof.f.mjs +40 -21
  193. package/fjs/media/revision/module.f.d.mts +78 -7
  194. package/fjs/media/revision/module.f.mjs +119 -12
  195. package/fjs/media/revision/proof.f.d.mts +10 -0
  196. package/fjs/media/revision/proof.f.mjs +88 -0
  197. package/fjs/media/revision/types.d.ts +34 -5
  198. package/fjs/media/type/module.f.d.mts +33 -15
  199. package/fjs/media/type/module.f.mjs +35 -29
  200. package/fjs/media/type/proof.f.d.mts +2 -1
  201. package/fjs/media/type/proof.f.mjs +30 -10
  202. package/fjs/module.f.mjs +29 -8
  203. package/fjs/nanvm/proof.f.mjs +3 -3
  204. package/fjs/nanvm/rust/module.f.mjs +1 -1
  205. package/fjs/nanvm/update/module.f.d.mts +4 -4
  206. package/fjs/nanvm/update/module.f.mjs +8 -9
  207. package/fjs/nanvm/update/proof.f.mjs +4 -3
  208. package/fjs/proof.f.d.mts +3 -3
  209. package/fjs/proof.f.mjs +36 -10
  210. package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
  211. package/fjs/protocol/json_rpc/module.f.mjs +3 -3
  212. package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
  213. package/fjs/protocol/mcp/module.f.d.mts +10 -13
  214. package/fjs/protocol/mcp/module.f.mjs +74 -58
  215. package/fjs/protocol/mcp/proof.f.d.mts +13 -4
  216. package/fjs/protocol/mcp/proof.f.mjs +193 -61
  217. package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
  218. package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
  219. package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
  220. package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
  221. package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
  222. package/fjs/protocol/mcp/types.d.ts +17 -6
  223. package/fjs/sul/id/module.f.d.mts +0 -1
  224. package/fjs/sul/id/module.f.mjs +2 -3
  225. package/fjs/sul/level/hash/module.f.mjs +2 -1
  226. package/fjs/sul/level/hash/proof.f.mjs +2 -2
  227. package/fjs/sul/module.f.mjs +18 -13
  228. package/fjs/text/code_point/module.f.d.mts +8 -0
  229. package/fjs/text/code_point/module.f.mjs +8 -1
  230. package/fjs/text/code_point/proof.f.d.mts +1 -0
  231. package/fjs/text/code_point/proof.f.mjs +11 -0
  232. package/fjs/text/sgr/module.f.d.mts +4 -6
  233. package/fjs/text/sgr/module.f.mjs +6 -7
  234. package/fjs/text/utf16/module.f.mjs +7 -2
  235. package/fjs/text/utf16/proof.f.mjs +3 -3
  236. package/fjs/text/utf8/module.f.mjs +4 -2
  237. package/fjs/types/array/module.f.mjs +14 -2
  238. package/fjs/types/bit_vec/module.f.d.mts +0 -2
  239. package/fjs/types/bit_vec/module.f.mjs +46 -32
  240. package/fjs/types/bit_vec/proof.f.mjs +2 -2
  241. package/fjs/types/btree/remove/module.f.mjs +1 -1
  242. package/fjs/types/btree/set/module.f.mjs +9 -11
  243. package/fjs/types/btree/set/proof.f.mjs +12 -0
  244. package/fjs/types/byte_set/module.f.d.mts +11 -4
  245. package/fjs/types/byte_set/module.f.mjs +14 -6
  246. package/fjs/types/byte_set/proof.f.mjs +7 -7
  247. package/fjs/types/function/compare/module.f.mjs +10 -3
  248. package/fjs/types/list/module.f.d.mts +1 -1
  249. package/fjs/types/list/module.f.mjs +1 -1
  250. package/fjs/types/nullable/module.f.d.mts +18 -4
  251. package/fjs/types/nullable/module.f.mjs +21 -4
  252. package/fjs/types/nullable/proof.f.d.mts +4 -0
  253. package/fjs/types/nullable/proof.f.mjs +15 -0
  254. package/fjs/types/object/module.f.d.mts +12 -2
  255. package/fjs/types/object/module.f.mjs +11 -1
  256. package/fjs/types/patricia_trie/module.f.mjs +26 -11
  257. package/fjs/types/result/module.f.d.mts +3 -3
  258. package/fjs/types/result/module.f.mjs +3 -3
  259. package/fjs/types/rtti/common/module.f.d.mts +25 -28
  260. package/fjs/types/rtti/common/module.f.mjs +36 -32
  261. package/fjs/types/rtti/common/proof.f.mjs +5 -5
  262. package/fjs/types/rtti/data/module.f.d.mts +14 -0
  263. package/fjs/types/rtti/data/module.f.mjs +25 -2
  264. package/fjs/types/rtti/data/proof.f.d.mts +1 -0
  265. package/fjs/types/rtti/data/proof.f.mjs +25 -2
  266. package/fjs/types/rtti/parse/module.f.d.mts +24 -14
  267. package/fjs/types/rtti/parse/module.f.mjs +37 -28
  268. package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
  269. package/fjs/types/rtti/parse/proof.f.mjs +33 -14
  270. package/fjs/types/rtti/proof.f.mjs +3 -1
  271. package/fjs/types/rtti/ts/module.f.mjs +13 -17
  272. package/fjs/types/rtti/ts/types.d.ts +14 -1
  273. package/fjs/types/rtti/validate/module.f.d.mts +81 -19
  274. package/fjs/types/rtti/validate/module.f.mjs +107 -61
  275. package/fjs/types/rtti/validate/proof.f.d.mts +13 -10
  276. package/fjs/types/rtti/validate/proof.f.mjs +186 -197
  277. package/fjs/types/sorted_set/module.f.d.mts +18 -0
  278. package/fjs/types/sorted_set/module.f.mjs +22 -0
  279. package/fjs/types/sorted_set/proof.f.d.mts +1 -0
  280. package/fjs/types/sorted_set/proof.f.mjs +16 -1
  281. package/fjs/types/uint8array/module.f.d.mts +1 -1
  282. package/fjs/types/uint8array/module.f.mjs +1 -1
  283. package/fjs/website/module.f.d.mts +3 -3
  284. package/fjs/website/module.f.mjs +4 -7
  285. package/fjs/website/proof.f.mjs +2 -1
  286. package/package.json +2 -2
  287. package/fjs/dev/package_json/module.f.d.mts +0 -39
  288. package/fjs/dev/package_json/module.f.mjs +0 -40
  289. package/fjs/dev/package_json/proof.f.d.mts +0 -6
  290. package/fjs/dev/package_json/proof.f.mjs +0 -32
  291. package/fjs/effects/eff/module.f.d.mts +0 -20
  292. package/fjs/effects/eff/module.f.mjs +0 -70
  293. package/fjs/effects/eff/proof.f.d.mts +0 -15
  294. package/fjs/effects/eff/proof.f.mjs +0 -69
  295. package/fjs/effects/eff/types.d.ts +0 -71
  296. package/fjs/types/rtti/validate/types.d.ts +0 -6
@@ -1,35 +1,49 @@
1
1
  /**
2
- * @import { Effect, Operation, OperationMap } from './types.ts'
2
+ * @import { Effect, Func, Operation } from './types.ts'
3
+ * @import { Result } from '../types/result/types.ts'
3
4
  */
4
5
 
5
- import { step, do_, foldStep, forEachStep, mapStep, match, okStep, history, pure, runPure, historyStep } from './module.f.mjs'
6
+ import {
7
+ catchStep, do_, foldStep, forEachStep, history, historyStep, mapStep, match,
8
+ partialMatch, pure, pureError, pureOk, resultMapStep, resultStep, runPure, step,
9
+ unwrapStep,
10
+ } from './module.f.mjs'
6
11
  import { error, ok } from '../types/result/module.f.mjs'
7
- import { assert, assertEq } from '../asserts/module.f.mjs'
12
+ import { assert, assertEq, todo } from '../asserts/module.f.mjs'
8
13
 
9
14
  /**
10
- * Asserts that `e` yields `expected` without performing a command. Exported so
11
- * `eff/proof.f.ts` shares this definition instead of repeating it.
15
+ * Asserts that `e` reaches `expected` without performing a command.
12
16
  *
13
17
  * Not `assertEq(runPure(e), [expected])`: `assertEq` compares with `===`, so a
14
- * freshly allocated `[expected]` is never equal to the returned option. Assert
15
- * the option's shape first, then compare the value inside it.
18
+ * freshly allocated option or `Result` is never equal to the returned one.
19
+ * Assert the option's shape first, then compare the value inside it.
20
+ *
16
21
  * @template {Operation} O
17
22
  * @template T
18
- * @param {Effect<O, T>} e
19
- * @param {T} expected
23
+ * @template E
24
+ * @param {Effect<O, T, E>} e
25
+ * @param {Result<T, E>} expected
20
26
  */
21
- export const assertPure = (e, expected) => {
27
+ const assertPure = (e, expected) => {
22
28
  const o = runPure(e)
23
29
  assert(o.length === 1, e)
24
- assertEq(o[0], expected)
30
+ assertEq(o[0][0], expected[0])
31
+ assertEq(o[0][1], expected[1])
25
32
  }
26
33
 
27
- /** @typedef {readonly['add', (a: number, b: number) => number]} _AddOp */
34
+ /**
35
+ * `Operation` requires a `Result` return, so a runner always has somewhere to
36
+ * answer `error(notImplemented)` — and that requirement is what lets an effect
37
+ * carry its error channel in the type rather than inside an opaque payload.
38
+ * @typedef {readonly['add', (a: number, b: number) => Result<number, string>]} _AddOp
39
+ */
28
40
 
29
- /** @type {(command: 'add') => (a: number, b: number) => Effect<_AddOp, number>} */
41
+ /** @type {(command: 'add') => (a: number, b: number) => Effect<_AddOp, number, string>} */
30
42
  const doAdd = do_
31
43
 
32
- const next = match(/** @type {OperationMap<_AddOp, number>} */ ({ add: (a, b) => a + b }))
44
+ const next = match({
45
+ add: (/** @type {number} */ a, /** @type {number} */ b) => ok(a + b),
46
+ })
33
47
 
34
48
  /**
35
49
  * An operation set whose command is any `string`, which is what a `Do` node
@@ -37,72 +51,143 @@ const next = match(/** @type {OperationMap<_AddOp, number>} */ ({ add: (a, b) =>
37
51
  * nothing stops it naming a member `map` inherits from `Object.prototype`
38
52
  * rather than an own handler. `match` must refuse those, and this type is how a
39
53
  * proof says so without an `as` cast.
40
- * @typedef {readonly[string, (a: number) => number]} _AnyOp
54
+ * @typedef {readonly[string, (a: number) => Result<number, string>]} _AnyOp
41
55
  */
42
56
 
43
- /** @type {(command: string) => (a: number) => Effect<_AnyOp, number>} */
57
+ /** @type {(command: string) => (a: number) => Effect<_AnyOp, number, string>} */
44
58
  const doAny = do_
45
59
 
46
- const anyNext = match(/** @type {OperationMap<_AnyOp, number>} */ ({ add: a => a + 1 }))
60
+ const anyNext = match({ add: (/** @type {number} */ a) => ok(a + 1) })
61
+
62
+ /**
63
+ * The same map, reached through the runner that may decline a command. The
64
+ * handler's return is annotated so it and `onMissing` agree on one `R` — a
65
+ * runner's answer type is shared by both, which is the whole reason
66
+ * `partialMatch` takes the injector from its caller.
67
+ */
68
+ const anyPartial = partialMatch(
69
+ /** @type {readonly string[]} */ (['add', 'sub']),
70
+ (/** @type {string} */ command) =>
71
+ /** @type {Result<number, string>} */ (error(`declined: ${command}`)),
72
+ )({
73
+ add: (/** @type {number} */ a) => /** @type {Result<number, string>} */ (ok(a + 1)),
74
+ })
75
+
76
+ // ── Composition ──────────────────────────────────────────────────────────────
77
+ /**
78
+ * A fallible operation, spelled the way every operation is spelled: the
79
+ * `Result` is in the command's declared return type, so `do_` already builds an
80
+ * `Effect` and the runner's handler already answers with `ok` / `error`.
81
+ * @typedef {readonly['div', (a: number, b: number) => Result<number, string>]} _DivOp
82
+ */
83
+
84
+ /**
85
+ * A second operation, so a chain can join two of them and the operation sets
86
+ * union.
87
+ * @typedef {readonly['neg', (a: number) => Result<number, string>]} _NegOp
88
+ */
89
+
90
+ /** @typedef {_DivOp | _NegOp} _Op */
91
+
92
+ /** @type {Func<_DivOp>} */
93
+ const div = do_('div')
94
+
95
+ /** @type {Func<_NegOp>} */
96
+ const neg = do_('neg')
97
+
98
+ const nextArith = match({
99
+ div: (/** @type {number} */ a, /** @type {number} */ b) =>
100
+ b === 0 ? error('div by zero') : ok(a / b),
101
+ neg: (/** @type {number} */ a) => ok(-a),
102
+ })
103
+
104
+ /**
105
+ * Runs an effect to completion against the two operations above — `asyncRun`'s
106
+ * loop without the `await`, which is all a synchronous runner is.
107
+ * @type {<T, E>(e: Effect<_Op, T, E>) => Result<T, E>}
108
+ */
109
+ const run = e => {
110
+ let current = e
111
+ while (true) {
112
+ const r = nextArith(current)
113
+ if (r[0] === 'done') { return r[1] }
114
+ current = r[2](r[1])
115
+ }
116
+ }
117
+
118
+ /**
119
+ * The `Result` an effect reaches without performing a command.
120
+ * @type {<O extends Operation, T, E>(e: Effect<O, T, E>) => Result<T, E>}
121
+ */
122
+ const pureResult = e => {
123
+ const o = runPure(e)
124
+ assert(o.length === 1, e)
125
+ return o[0]
126
+ }
127
+
128
+ /**
129
+ * The `ok` value an effect reaches without performing a command.
130
+ * @type {<O extends Operation, T, E>(e: Effect<O, T, E>) => T}
131
+ */
132
+ const unwrapPure = e => {
133
+ const r = pureResult(e)
134
+ assert(r[0] === 'ok', r)
135
+ return r[1]
136
+ }
137
+
138
+ /** @type {<T, E>(r: Result<T, E>, expected: T) => void} */
139
+ const assertOk = (r, expected) => {
140
+ assert(r[0] === 'ok', r)
141
+ assertEq(r[1], expected)
142
+ }
143
+
144
+ /** @type {<T, E>(r: Result<T, E>, expected: E) => void} */
145
+ const assertError = (r, expected) => {
146
+ assert(r[0] === 'error', r)
147
+ assertEq(r[1], expected)
148
+ }
149
+
150
+ /** @type {(v: number) => Effect<never, number, string>} */
151
+ const positive = v => v > 0 ? pureOk(v) : pureError('not positive')
152
+
153
+ /** @type {(v: number) => Effect<never, number, number>} */
154
+ const small = v => v < 10 ? pureOk(v) : pureError(v)
155
+
156
+ /**
157
+ * Two adjacent links failing in different ways. The annotation is the claim:
158
+ * the chain's error channel is the **union** of theirs, so neither link had to
159
+ * be pre-widened to the other's error type.
160
+ * @type {(v: number) => Effect<never, number, string | number>}
161
+ */
162
+ const checked = v => {
163
+ const x0 = step(pureOk(v), positive)
164
+ return step(x0, small)
165
+ }
166
+
167
+ /**
168
+ * The anything-accepting renderer {@link unwrapStep}'s doc calls an escape
169
+ * hatch. It is the honest choice *here* — these proofs are about `unwrapStep`
170
+ * itself, not about any particular channel — and the wrong one almost anywhere
171
+ * else, since accepting every error is what stops a widened channel from being
172
+ * a compile error.
173
+ *
174
+ * @type {(e: unknown) => string}
175
+ */
176
+ const show = e => `${e}`
47
177
 
48
178
  export const proof = {
49
- foldStep: {
50
- empty: () => {
51
- const e = foldStep(pure(/** @type {readonly number[]} */ ([])), 10, x => s => pure(s + x))
52
- assertPure(e, 10)
53
- },
54
- threadsState: () => {
55
- const e = foldStep(pure([1, 2, 3, 4]), 0, x => s => pure(s + x))
56
- assertPure(e, 10)
57
- },
58
- order: () => {
59
- const e = foldStep(pure(['a', 'b', 'c']), '', x => s => pure(s + x))
60
- assertPure(e, 'abc')
61
- },
62
- },
63
- forEachStep: {
64
- empty: () => {
65
- const e = forEachStep(pure(/** @type {readonly number[]} */ ([])), () => pure(undefined))
66
- assertPure(e, undefined)
67
- },
68
- runs: () => {
69
- const e = forEachStep(pure([1, 2, 3]), () => pure(undefined))
70
- assertPure(e, undefined)
71
- },
72
- },
73
- okStep: {
179
+ runPure: {
74
180
  ok: () => {
75
- const e = step(pure(ok(5)), okStep((/** @type {number} */ v) => pure(ok(v * 2))))
76
- const o = runPure(e)
77
- assert(o.length === 1, e)
78
- const [r] = o
79
- assert(r[0] === 'ok', r)
80
- assertEq(r[1], 10)
181
+ assertPure(pure(ok(5)), ok(5))
81
182
  },
82
183
  error: () => {
83
- const e = step(
84
- pure(error(/** @type {string} */ ('oops'))),
85
- okStep(/** @type {(value: number) => Effect<never, import('../types/result/types.ts').Result<number, string>>} */
86
- (v => pure(ok(v * 2)))))
87
- const o = runPure(e)
88
- assert(o.length === 1, e)
89
- const [r] = o
90
- assert(r[0] === 'error', r)
91
- assertEq(r[1], 'oops')
92
- },
93
- },
94
- runPure: {
95
- pure: () => {
96
- const o = runPure(pure(5))
97
- assert(o.length === 1, o)
98
- assertEq(o[0], 5)
184
+ assertPure(pure(error('boom')), error('boom'))
99
185
  },
100
- // A pure `null` is `[null]`, never `[]`. Collapsing the two is what a
101
- // `T | null` result would do, and why the option is tagged.
186
+ // A pure `null` is `[ok(null)]`, never `[]`. Collapsing the two is what
187
+ // a bare `T | null` result would do, and why the option is tagged
188
+ // separately from the `Result` inside it.
102
189
  pureNull: () => {
103
- const o = runPure(pure(null))
104
- assertEq(o.length, 1, o)
105
- assertEq(o[0], null)
190
+ assertPure(pure(ok(null)), ok(null))
106
191
  },
107
192
  do_: () => {
108
193
  assertEq(runPure(doAdd('add')(2, 3)).length, 0)
@@ -110,8 +195,8 @@ export const proof = {
110
195
  },
111
196
  // The one place a `Do` node is opened on purpose: `do_` builds the command,
112
197
  // the payload it was called with, and a continuation that resumes with the
113
- // command's output. Everything else goes through `step`, `match`, or
114
- // `runPure`.
198
+ // command's output. Everything else goes through `match`, `partialMatch`,
199
+ // or `runPure`.
115
200
  doNode: () => {
116
201
  const e = doAdd('add')(2, 3)
117
202
  assert(typeof e !== 'function', e)
@@ -120,21 +205,34 @@ export const proof = {
120
205
  const [a, b] = payload
121
206
  assertEq(a, 2, payload)
122
207
  assertEq(b, 3, payload)
123
- assertPure(continuation(5), 5)
208
+ // The command's output is the whole `Result` — `Operation` requires one
209
+ // so a runner always has somewhere to answer a refusal — so this
210
+ // resumes with `ok(5)` rather than a bare `5`.
211
+ assertPure(continuation(ok(5)), ok(5))
212
+ },
213
+ // A runner hands a failed command back through the *ordinary* continuation,
214
+ // which is what makes `error(notImplemented)` something a program can
215
+ // recover from. Pinned here because it is the property the whole error
216
+ // channel rests on: had the representation short-circuited, there would be
217
+ // nothing for `catchStep` to catch.
218
+ failedCommandResumes: () => {
219
+ const e = doAdd('add')(2, 3)
220
+ assert(typeof e !== 'function', e)
221
+ assertPure(e.continuation(error('declined')), error('declined'))
124
222
  },
125
223
  match: {
126
224
  done: () => {
127
- const r = next(pure(7))
225
+ const r = next(pure(ok(7)))
128
226
  assert(r[0] === 'done', r)
129
- assertEq(r[1], 7)
227
+ assertEq(r[1][1], 7)
130
228
  },
131
229
  cont: () => {
132
230
  const r = next(doAdd('add')(2, 3))
133
231
  assert(r[0] === 'cont', r)
134
- assertEq(r[1], 5)
232
+ assertEq(r[1][1], 5)
135
233
  const r2 = next(r[2](r[1]))
136
234
  assert(r2[0] === 'done', r2)
137
- assertEq(r2[1], 5)
235
+ assertEq(r2[1][1], 5)
138
236
  },
139
237
  ownCommand: () => {
140
238
  // The same map the two cases below dispatch against: an own
@@ -142,7 +240,7 @@ export const proof = {
142
240
  // inherited names, not a map that dispatches nothing.
143
241
  const r = anyNext(doAny('add')(41))
144
242
  assert(r[0] === 'cont', r)
145
- assertEq(r[1], 42)
243
+ assertEq(r[1][1], 42)
146
244
  },
147
245
  // A `command` naming an `Object.prototype` member must not dispatch to
148
246
  // the inherited value. `map['constructor']` is `Object` and
@@ -158,77 +256,259 @@ export const proof = {
158
256
  },
159
257
  },
160
258
  },
259
+ partialMatch: {
260
+ // A command the runner does implement dispatches as usual.
261
+ implemented: () => {
262
+ const r = anyPartial(doAny('add')(41))
263
+ assert(r[0] === 'cont', r)
264
+ assertEq(r[1][1], 42)
265
+ },
266
+ // A command in the set with no handler is an *outcome*: the answer
267
+ // travels back through the ordinary continuation, and the program
268
+ // decides what a runner without that capability means for it.
269
+ declined: () => {
270
+ const r = anyPartial(doAny('sub')(1))
271
+ assert(r[0] === 'cont', r)
272
+ assert(r[1][0] === 'error' && r[1][1] === 'declined: sub', r)
273
+ assertPure(r[2](r[1]), error('declined: sub'))
274
+ },
275
+ // A command outside the set is a malformed node, not a capability the
276
+ // runner lacks, and still panics.
277
+ throw: {
278
+ unknownCommand: () => {
279
+ anyPartial(doAny('nope')(1))
280
+ },
281
+ },
282
+ },
283
+ pureOk: () => {
284
+ assertOk(pureResult(pureOk(5)), 5)
285
+ },
286
+ pureError: () => {
287
+ assertError(pureResult(pureError('nope')), 'nope')
288
+ },
161
289
  step: {
162
- pure: () => {
163
- assertPure(step(pure(3), v => pure(v + 1)), 4)
290
+ ok: () => {
291
+ const e = step(pureOk(5), v => pureOk(v * 2))
292
+ assertOk(pureResult(e), 10)
293
+ },
294
+ // The continuation does not run on an `error`: `todo` throws if it
295
+ // does, so propagation is what keeps this proof passing.
296
+ propagates: () => {
297
+ const e = step(pureError('boom'), todo)
298
+ assertError(pureResult(e), 'boom')
299
+ },
300
+ // ...and the error that comes out is the very tuple that went in,
301
+ // rather than an equal one rebuilt to retag it.
302
+ errorTupleIsUnchanged: () => {
303
+ const e = pureError('boom')
304
+ assertEq(pureResult(step(e, todo)), pureResult(e))
164
305
  },
165
306
  chain: () => {
166
- // Chains as step(step(e, f), g), raw effect in and out.
167
- assertPure(step(step(pure(3), v => pure(v + 1)), v => pure(v * 2)), 8)
307
+ // Flat, one name per link the chain of `step`s reads in
308
+ // evaluation order.
309
+ const x0 = step(pureOk(3), v => pureOk(v + 1))
310
+ const x1 = step(x0, v => pureOk(v * 2))
311
+ assertOk(pureResult(x1), 8)
168
312
  },
313
+ // A `Do` node keeps its command, and the continuation resumes with the
314
+ // operation's `ok` value rather than with the `Result` around it.
169
315
  overDo: () => {
170
- // Stepping a Do node preserves the command and threads the result
171
- // through the rebuilt continuation.
172
- const e = step(doAdd('add')(2, 3), r => pure(r * 10))
173
- const r = next(e)
174
- assert(r[0] === 'cont', r)
175
- assertEq(r[1], 5)
176
- assertPure(r[2](r[1]), 50)
316
+ const e = step(div(6, 3), v => pureOk(v * 10))
317
+ assertOk(run(e), 20)
318
+ },
319
+ // The same chain when the operation itself fails: the command was
320
+ // performed, its error propagates, and the continuation never runs.
321
+ overFailedDo: () => {
322
+ // `todo` never returns, so it pins none of the continuation's type
323
+ // parameters; the annotation supplies the operation set `run` needs.
324
+ /** @type {Effect<_DivOp, never, string>} */
325
+ const e = step(div(1, 0), todo)
326
+ assertError(run(e), 'div by zero')
327
+ },
328
+ // Adjacent links performing different commands: the operation sets
329
+ // union, so one runner interprets the whole chain.
330
+ joinsOperations: () => {
331
+ /** @type {Effect<_Op, number, string>} */
332
+ const e = step(div(6, 3), neg)
333
+ assertOk(run(e), -2)
334
+ },
335
+ mixedErrorsOk: () => {
336
+ assertOk(pureResult(checked(5)), 5)
337
+ },
338
+ // The first link's error type...
339
+ mixedErrorsFirst: () => {
340
+ assertError(pureResult(checked(-1)), 'not positive')
341
+ },
342
+ // ...and the second's, in the same chain and the same channel.
343
+ mixedErrorsSecond: () => {
344
+ assertError(pureResult(checked(50)), 50)
177
345
  },
178
346
  },
179
- mapStep: {
180
- pure: () => {
181
- assertPure(mapStep(pure(3), v => v + 1), 4)
347
+ catchStep: {
348
+ recovers: () => {
349
+ const e = catchStep(pureError('boom'), m => pureOk(m.length))
350
+ assertOk(pureResult(e), 4)
182
351
  },
183
- constant: () => {
184
- // The `() => v` shape a `constStep` would have covered.
185
- assertPure(mapStep(pure('ignored'), () => 1), 1)
352
+ // The success passes through untouched — `todo` proves the recovery
353
+ // does not run and it is the same tuple, as in `step`'s mirror case.
354
+ preservesOk: () => {
355
+ const e = pureOk(5)
356
+ assertEq(pureResult(catchStep(e, todo)), pureResult(e))
357
+ },
358
+ // Recovery after a performed command, which is the shape a runner's
359
+ // `NotImplemented` takes: the program regains control and chooses what
360
+ // the failure means for it.
361
+ overFailedDo: () => {
362
+ const e = catchStep(div(1, 0), () => pureOk(0))
363
+ assertOk(run(e), 0)
364
+ },
365
+ // The success channel unions `T | R`: a recovery may yield a different
366
+ // type than the value it stands in for, and the error channel becomes
367
+ // `f`'s alone — `never` here, since every error is handled.
368
+ unionsSuccess: () => {
369
+ /** @type {Effect<never, number | string, never>} */
370
+ const e = catchStep(pureError('boom'), m => pureOk(m))
371
+ assertOk(pureResult(e), 'boom')
372
+ },
373
+ },
374
+ resultStep: {
375
+ // Both branches reach `f`, which decides the outcome — including
376
+ // turning an `error` into an `ok`.
377
+ ok: () => {
378
+ const e = resultStep(pureOk(5), ([tag]) => pureOk(tag))
379
+ assertOk(pureResult(e), 'ok')
380
+ },
381
+ error: () => {
382
+ const e = resultStep(pureError('boom'), ([tag]) => pureOk(tag))
383
+ assertOk(pureResult(e), 'error')
186
384
  },
187
385
  overDo: () => {
188
- // A projection over a `Do` node keeps the command intact and is
189
- // applied to the command's output when the continuation resumes.
190
- const r = next(mapStep(doAdd('add')(2, 3), v => v * 10))
191
- assert(r[0] === 'cont', r)
192
- assertEq(r[1], 5)
193
- assertPure(r[2](r[1]), 50)
386
+ const e = resultStep(div(1, 0), ([tag]) => pureOk(tag))
387
+ assertOk(run(e), 'error')
194
388
  },
195
389
  },
196
390
  historyStep: {
197
- pure: () => {
198
- const o = runPure(historyStep(history(pure(3)), v => pure(v * 2)))
199
- assert(o.length === 1, o)
200
- const [[result, param]] = o
391
+ // The chain stays flat: the last link reads a value bound two links
392
+ // back out of the tuple rather than out of an enclosing closure.
393
+ chain: () => {
394
+ const h0 = history(pureOk(1))
395
+ const h1 = historyStep(h0, x => pureOk(x + 1))
396
+ const h2 = historyStep(h1, (y, x) => pureOk(`${x}${y}`))
397
+ assertOk(pureResult(mapStep(h2, ([z]) => z)), '12')
398
+ },
399
+ // The history carries `ok` values, so a later link reads them without
400
+ // asking whether they are there...
401
+ carriesValues: () => {
402
+ const h0 = historyStep(history(pureOk(3)), x => pureOk(x * 2))
403
+ const [result, param] = unwrapPure(h0)
201
404
  assertEq(param, 3)
202
405
  assertEq(result, 6)
203
406
  },
407
+ // ...because a failed link short-circuits instead of contributing one.
408
+ propagates: () => {
409
+ const h0 = historyStep(history(pureOk(3)), () => pureError('boom'))
410
+ assertError(pureResult(historyStep(h0, todo)), 'boom')
411
+ },
412
+ // A failure in the effect the history starts from never reaches `f`.
413
+ propagatesFromHead: () => {
414
+ assertError(pureResult(historyStep(history(pureError('boom')), todo)), 'boom')
415
+ },
416
+ // Over a `Do` node: the captured value survives the command boundary.
204
417
  overDo: () => {
205
- // The captured value survives a command boundary: the history is
206
- // rebuilt inside the continuation rather than lost when `e` is a Do.
207
- const c = next(historyStep(history(doAdd('add')(2, 3)), r => pure(r * 10)))
208
- assert(c[0] === 'cont', c)
209
- assertEq(c[1], 5)
210
- const o = runPure(c[2](c[1]))
211
- assert(o.length === 1, o)
212
- const [[result, param]] = o
213
- assertEq(param, 5)
214
- assertEq(result, 50)
418
+ const h0 = historyStep(history(div(6, 3)), r => pureOk(r * 10))
419
+ const [result, param] = run(h0)[1]
420
+ assertEq(param, 2)
421
+ assertEq(result, 20)
215
422
  },
216
- chain: () => {
217
- // `historyStep` takes a history and returns one, so link two is
218
- // spelled exactly like link one. The tuple is newest first, so a
219
- // destructuring reads reverse-chronologically.
220
- const a = historyStep(history(pure(1)), x => pure(x + 1))
221
- const b = historyStep(a, (result, param) => pure(result + param))
222
- assertPure(
223
- step(b, ([z, y, x]) => pure(`${x}${y}${z}`)),
224
- '123')
225
- },
226
- fReceivesWholeHistory: () => {
227
- // `f` is handed the whole history spread as arguments, not just the
228
- // most recent value - which is what lets a later link reach back.
229
- const a = historyStep(history(pure(1)), x => pure(x + 1))
230
- const b = historyStep(a, (...p) => pure(p[1] * 100 + p[0]))
231
- assertPure(step(b, ([result]) => pure(result)), 102)
423
+ },
424
+ foldStep: {
425
+ empty: () => {
426
+ assertOk(pureResult(foldStep(pureOk([]), 10, x => s => pureOk(s + x))), 10)
427
+ },
428
+ threadsState: () => {
429
+ assertOk(pureResult(foldStep(pureOk([1, 2, 3, 4]), 0, x => s => pureOk(s + x))), 10)
430
+ },
431
+ // The first failure stops the fold: `4` never reaches the accumulator,
432
+ // and the error is the result.
433
+ shortCircuits: () => {
434
+ const e = foldStep(pureOk([1, 2, 4]),
435
+ 0,
436
+ x => s => x === 2 ? pureError('two') : pureOk(s + x))
437
+ assertError(pureResult(e), 'two')
438
+ },
439
+ },
440
+ forEachStep: {
441
+ empty: () => {
442
+ assertOk(pureResult(forEachStep(pureOk([]), todo)), undefined)
443
+ },
444
+ runs: () => {
445
+ assertOk(pureResult(forEachStep(pureOk([1, 2, 3]), () => pureOk(undefined))), undefined)
446
+ },
447
+ // Where a `Result`-blind `forEachStep` would run every item regardless,
448
+ // this one stops — the difference a `void` accumulator hides.
449
+ stopsAtTheFirstError: () => {
450
+ const e = forEachStep(pureOk([1, 2, 3]),
451
+ x => x === 2 ? pureError('two') : pureOk(undefined))
452
+ assertError(pureResult(e), 'two')
453
+ },
454
+ },
455
+ unwrapStep: {
456
+ // An `ok` passes through untouched — what the panic empties is the
457
+ // error channel, so the value is still carried in an `ok`.
458
+ ok: () => {
459
+ assertOk(pureResult(unwrapStep(pureOk(5), show)), 5)
460
+ },
461
+ // An `error` is a panic — the policy the name exists to make greppable.
462
+ // It throws where the composition is written, since `mapStep` forces a
463
+ // `Pure` head immediately.
464
+ throw: {
465
+ error: () => {
466
+ unwrapStep(pureError('boom'), show)
467
+ },
468
+ },
469
+ },
470
+ mapStep: {
471
+ ok: () => {
472
+ assertOk(pureResult(mapStep(pureOk(3), v => v + 1)), 4)
473
+ },
474
+ // An `error` is passed through unchanged — the same tuple, and `f` is
475
+ // never applied to it.
476
+ error: () => {
477
+ const e = pureError('boom')
478
+ assertEq(pureResult(mapStep(e, todo)), pureResult(e))
479
+ },
480
+ // A projection over a `Do` node keeps the command intact and applies
481
+ // `f` to the operation's `ok` value when the continuation resumes.
482
+ overDo: () => {
483
+ assertOk(run(mapStep(div(6, 3), v => v * 10)), 20)
484
+ },
485
+ },
486
+ resultMapStep: {
487
+ // Both branches reach `f`, which is the difference from `mapStep`: the
488
+ // error is handed over rather than passed around.
489
+ ok: () => {
490
+ assertOk(pureResult(resultMapStep(pureOk(3), r => ok(r[0]))), 'ok')
491
+ },
492
+ error: () => {
493
+ assertOk(pureResult(resultMapStep(pureError('boom'), r => ok(r[0]))), 'error')
494
+ },
495
+ // `f` chooses the outgoing channel, so a failure can be turned into a
496
+ // success — the discard `mapStep` cannot express, written as a function
497
+ // that says it took both branches.
498
+ absorbs: () => {
499
+ assertOk(pureResult(resultMapStep(pureError('boom'), () => ok(0))), 0)
500
+ },
501
+ // ...and the reverse: a success can be rejected.
502
+ rejects: () => {
503
+ assertError(pureResult(resultMapStep(pureOk(3), () => error('no'))), 'no')
504
+ },
505
+ // Over a `Do` node the command survives and `f` runs on the operation's
506
+ // whole answer, including when that answer is the operation's failure.
507
+ overDo: () => {
508
+ assertOk(run(resultMapStep(div(6, 3), r => ok(r[1]))), 2)
509
+ },
510
+ overFailedDo: () => {
511
+ assertOk(run(resultMapStep(div(1, 0), r => ok(r[0]))), 'error')
232
512
  },
233
513
  },
234
514
  }