ece0fc4491038b19533f3eb18e9a039c4f23798e307a2c9edc90919a389697a3.tri (21471B)
1 !export * 2 -- 1. t t a b -> a 3 -- 2. t (t a) b c -> a c (b c) 4 -- 3a. t (t a b) c t -> a 5 -- 3b. t (t a b) c (t u) -> b u 6 -- 3c. t (t a b) c (t u v) -> c u v 7 8 false = t 9 _ = t 10 true = t t 11 id a = a 12 const a b = a 13 pair = t 14 if cond then else = t (t else (t t then)) t cond 15 16 y = ((mut wait fun : wait mut (x : fun (wait mut x))) 17 (x : x x) 18 (a0 a1 a2 : t (t a0) (t t a2) a1)) 19 20 compose f g x = f (g x) 21 22 triage leaf stem fork = t (t leaf stem) fork 23 test = triage "Leaf" (_ : "Stem") (_ _ : "Fork") 24 25 matchBool = (onTrue onFalse : triage 26 onFalse 27 (_ : onTrue) 28 (_ _ : onTrue) 29 ) 30 31 lAnd = (triage 32 (_ : false) 33 (_ x : x) 34 (_ _ x : x)) 35 36 lOr = (triage 37 (x : x) 38 (_ _ : true) 39 (_ _ _ : true)) 40 41 matchPair a = triage _ _ a 42 43 fst p = matchPair takeFirst p 44 where takeFirst a b = a 45 snd p = matchPair takeSecond p 46 where takeSecond a b = b 47 48 resultIsOk result = 49 matchResult (errR rest : false) (val rest : true) result 50 51 resultIsErr result = 52 matchResult (errR rest : true) (val rest : false) result 53 54 not? = matchBool false true 55 and? = matchBool id (_ : false) 56 57 or? = (x z : 58 matchBool 59 (matchBool true true z) 60 (matchBool true false z) 61 x) 62 63 xor? = (x z : 64 matchBool 65 (matchBool false true z) 66 (matchBool true false z) 67 x) 68 69 equal? = y (self : triage 70 (triage 71 true 72 (_ : false) 73 (_ _ : false)) 74 (ax : 75 triage 76 false 77 (self ax) 78 (_ _ : false)) 79 (ax ay : 80 triage 81 false 82 (_ : false) 83 (bx by : lAnd (self ax bx) (self ay by)))) 84 85 succ = y (self : 86 triage 87 1 88 t 89 (triage 90 (t (t t)) 91 (_ tail : t t (self tail)) 92 t)) 93 94 ok value rest = pair true (pair value rest) 95 err msg rest = pair false (pair msg rest) 96 97 matchResult errCase okCase result = 98 matchPair 99 (tag payload : 100 matchPair 101 (value rest : 102 matchBool 103 (okCase value rest) 104 (errCase value rest) 105 tag) 106 payload) 107 result 108 109 -- --------------------------------------------------------------------------- 110 -- Maybe / Option type 111 -- --------------------------------------------------------------------------- 112 113 nothing = t 114 just x = t x 115 116 matchMaybe nothingCase justCase maybe = 117 triage 118 nothingCase 119 justCase 120 (_ _ : nothingCase) 121 maybe 122 123 maybe default f m = matchMaybe default f m 124 maybeMap f m = matchMaybe nothing (x : just (f x)) m 125 maybeBind m f = matchMaybe nothing f m 126 maybeOr default m = matchMaybe default id m 127 maybe? = matchMaybe false (_ : true) 128 129 -- --------------------------------------------------------------------------- 130 -- Lazy eliminators 131 -- 132 -- A strict eliminator evaluates both branches because they are ordinary 133 -- arguments. Give a branch that recurses, looks something up, or builds 134 -- structure to one of these instead: it becomes a thunk and only the selected 135 -- branch is ever applied. 136 -- --------------------------------------------------------------------------- 137 138 lazyBool = (thenK elseK cond : 139 ((chosen : chosen t) 140 (matchBool 141 thenK 142 elseK 143 cond))) 144 145 -- `triage` selects a thunk directly: a cons is a Fork, so the cons case sits 146 -- in the fork slot, exactly as in `matchList` below. 147 lazyList = (nilK consK xs : 148 ((chosen : chosen t) 149 (triage 150 nilK 151 _ 152 (h r : (_ : consK h r)) 153 xs))) 154 155 lazyMaybe = (noneK someK m : 156 ((chosen : chosen t) 157 (matchMaybe 158 noneK 159 (x : (_ : someK x)) 160 m))) 161 162 lazyResult = (errK okK result : 163 ((chosen : chosen t) 164 (matchResult 165 (code rest : (_ : errK code rest)) 166 (value rest : (_ : okK value rest)) 167 result))) 168 169 -- --------------------------------------------------------------------------- 170 -- Basic arithmetic 171 -- --------------------------------------------------------------------------- 172 173 ifLazy = (cond thenK elseK : 174 matchBool 175 (thenK t) 176 (elseK t) 177 cond) 178 179 andLazy? = (a bK : 180 ifLazy 181 a 182 bK 183 (_ : false)) 184 185 pred_ = y (self : triage 186 0 187 0 188 (bit rest : 189 ifLazy 190 bit 191 (_ : matchBool 192 (t t rest) 193 0 194 rest) 195 (_ : t (t t) (self rest)))) 196 197 pred @nat? =@nat? pred_ 198 199 isZero_? = triage true (_ : false) (_ _ : false) 200 201 isZero? @nat? =@bool? isZero_? 202 203 add @nat? @nat? =@nat? (y (self x y : 204 triage 205 y 206 (_ : succ y) 207 (_ _ : succ (self (pred_ x) y)) 208 x)) 209 210 sub @nat? @nat? =@nat? y (self a b : 211 ifLazy 212 (isZero_? b) 213 (_ : a) 214 (_ : self (pred_ a) (pred_ b))) 215 216 lte_? = y (self a b : 217 ifLazy 218 (isZero_? a) 219 (_ : true) 220 (_ : 221 ifLazy 222 (isZero_? b) 223 (_ : false) 224 (_ : self (pred_ a) (pred_ b)))) 225 226 lte? @nat? @nat? =@bool? lte_? 227 228 gte_? = a b : lte_? b a 229 230 gte? @nat? @nat? =@bool? gte_? 231 232 lt_? = a b : and? (lte_? a b) (not? (equal? a b)) 233 234 lt? @nat? @nat? =@bool? lt_? 235 236 gt_? = a b : lt_? b a 237 238 gt? @nat? @nat? =@bool? gt_? 239 240 mul @nat? @nat? =@nat? y (self a b : 241 ifLazy 242 (isZero_? b) 243 (_ : 0) 244 (_ : add a (self a (pred_ b)))) 245 246 div @nat? @nat? =@nat? y (self a b : 247 ifLazy 248 (isZero_? b) 249 (_ : 0) 250 (_ : ifLazy 251 (lt_? a b) 252 (_ : 0) 253 (_ : succ (self (sub a b) b)))) 254 255 mod @nat? @nat? =@nat? y (self a b : 256 ifLazy 257 (isZero_? b) 258 (_ : 0) 259 (_ : ifLazy 260 (lt_? a b) 261 (_ : a) 262 (_ : self (sub a b) b))) 263 264 pow @nat? @nat? =@nat? y (self a b : 265 ifLazy 266 (isZero_? b) 267 (_ : 1) 268 (_ : mul a (self a (pred_ b)))) 269 270 even? n = (triage 271 true 272 (_ : false) 273 (bit _ : isZero_? bit) 274 n) 275 276 odd? = (n : not? (even? n)) 277 278 min @nat? @nat? =@nat? (a b : ifLazy (lte_? a b) (_ : a) (_ : b)) 279 280 max @nat? @nat? =@nat? (a b : ifLazy (lte_? a b) (_ : b) (_ : a)) 281 282 -- --------------------------------------------------------------------------- 283 -- Result combinators 284 -- --------------------------------------------------------------------------- 285 286 mapResult = (f result : 287 matchResult 288 (code rest : err code rest) 289 (value rest : ok (f value) rest) 290 result) 291 292 bindResult = (result f : 293 matchResult 294 (code rest : err code rest) 295 (value rest : f value rest) 296 result) 297 298 resultOr = (default result : 299 matchResult 300 (_ _ : default) 301 (value _ : value) 302 result) 303 304 resultMapErr = (f result : 305 matchResult 306 (code rest : err (f code) rest) 307 (value rest : ok value rest) 308 result) 309 310 -- --------------------------------------------------------------------------- 311 -- List 312 -- --------------------------------------------------------------------------- 313 314 matchList = a b : triage a _ b 315 316 emptyList? = matchList true (_ _ : false) 317 head xs@(nonEmptyListOf anyC) =@anyC matchList t (h _ : h) xs 318 tail xs@(nonEmptyListOf anyC) =@(listOf anyC) matchList t (_ r : r) xs 319 320 append_ self xs ys = 321 matchList 322 ys 323 (h r : pair h (self r ys)) 324 xs 325 append = xs ys : y append_ xs ys 326 327 lExist?_ self x xs = 328 matchList 329 false 330 (h r : or? (equal? x h) (self x r)) 331 xs 332 lExist? = x xs : y lExist?_ x xs 333 334 -- Keep these eliminators: patterned traversal has higher measured runtime and 335 -- allocation costs here. Local workers capture callbacks rather than threading 336 -- them through every recursive call. 337 map f xs = (let rec 338 walk remaining = (matchList 339 t 340 (h r : pair (f h) (walk r)) 341 remaining) 342 in walk xs) 343 344 filter f xs = (let rec 345 walk remaining = (matchList 346 t 347 (h r : matchBool (pair h (walk r)) (walk r) (f h)) 348 remaining) 349 in walk xs) 350 351 foldl f initial xs = (let rec 352 walk remaining acc = (matchList 353 acc 354 (h r : walk r (f acc h)) 355 remaining) 356 in walk xs initial) 357 358 foldr_ self l f x = 359 matchList 360 x 361 (h r : f (self r f x) h) 362 l 363 foldr = f x l : y foldr_ l f x 364 365 length_ self xs = 366 matchList 367 0 368 (_ r : succ (self r)) 369 xs 370 length @(listOf anyC) =@nat? y length_ 371 372 reverse xs = (let rec 373 walk remaining acc = (matchList 374 acc 375 (h r : walk r (pair h acc)) 376 remaining) 377 in walk xs t) 378 379 snoc_ self x xs = 380 matchList 381 (pair x t) 382 (h r : pair h (self x r)) 383 xs 384 snoc = x xs : y snoc_ x xs 385 386 count_ self x xs = 387 matchList 388 0 389 (h r : 390 matchBool 391 (succ (self x r)) 392 (self x r) 393 (equal? x h)) 394 xs 395 count = x xs : y count_ x xs 396 397 last_ self xs = 398 matchList 399 t 400 (h r : 401 matchBool 402 h 403 (self r) 404 (emptyList? r)) 405 xs 406 last @(nonEmptyListOf anyC) =@anyC y last_ 407 408 all?_ self pred xs = 409 matchList 410 true 411 (h r : and? (pred h) (self pred r)) 412 xs 413 all? = pred xs : y all?_ pred xs 414 415 any?_ self pred xs = 416 matchList 417 false 418 (h r : or? (pred h) (self pred r)) 419 xs 420 any? = pred xs : y any?_ pred xs 421 422 intersect = xs ys : filter (x : lExist? x ys) xs 423 424 nth_ self xs n i = 425 matchList 426 t 427 (h r : 428 matchBool 429 h 430 (self r n (succ i)) 431 (equal? i n)) 432 xs 433 nth = n xs : y nth_ xs n 0 434 435 headMaybe = matchList nothing (h _ : just h) 436 437 lastMaybe_ self xs = 438 matchList 439 nothing 440 (h r : 441 matchBool 442 (just h) 443 (self r) 444 (emptyList? r)) 445 xs 446 lastMaybe = xs : y lastMaybe_ xs 447 448 nthMaybe_ self xs n i = 449 matchList 450 nothing 451 (h r : 452 matchBool 453 (just h) 454 (self r n (succ i)) 455 (equal? i n)) 456 xs 457 nthMaybe = n xs : y nthMaybe_ xs n 0 458 459 take_ self xs n i = 460 matchList 461 t 462 (h r : 463 matchBool 464 t 465 (pair h (self r n (succ i))) 466 (equal? i n)) 467 xs 468 take = n xs : y take_ xs n 0 469 470 drop_ self xs n i = 471 matchBool 472 xs 473 (matchList 474 t 475 (_ r : self r n (succ i)) 476 xs) 477 (equal? i n) 478 drop = n xs : y drop_ xs n 0 479 480 splitAt = n xs : pair (take n xs) (drop n xs) 481 482 concatMap_ self f xs = 483 matchList 484 t 485 (h r : append (f h) (self f r)) 486 xs 487 concatMap = f xs : y concatMap_ f xs 488 489 find_ self pred xs = 490 matchList 491 nothing 492 (h r : 493 matchBool 494 (just h) 495 (self pred r) 496 (pred h)) 497 xs 498 find = pred xs : y find_ pred xs 499 500 partition_ self pred xs trues falses = 501 matchList 502 (pair (reverse trues) (reverse falses)) 503 (h r : 504 matchBool 505 (self pred r (pair h trues) falses) 506 (self pred r trues (pair h falses)) 507 (pred h)) 508 xs 509 partition = pred xs : y partition_ pred xs t t 510 511 strLength = length 512 strAppend = append 513 strEq? = equal? 514 strEmpty? = emptyList? 515 516 startsWith?_ self prefix input = 517 matchList 518 true 519 (ph pr : 520 matchList 521 false 522 (sh sr : 523 matchBool 524 (self pr sr) 525 false 526 (equal? ph sh)) 527 input) 528 prefix 529 startsWith? = prefix input : y startsWith?_ prefix input 530 531 endsWith? = prefix str : startsWith? (reverse prefix) (reverse str) 532 533 contains?_ self needle haystack = 534 matchBool 535 true 536 (matchList 537 false 538 (_ r : self needle r) 539 haystack) 540 (startsWith? needle haystack) 541 contains? = needle haystack : y contains?_ needle haystack 542 543 sum @(listOf nat?) =@nat? foldl (acc x : add x acc) 0 544 product @(listOf nat?) =@nat? foldl (acc x : mul x acc) 1 545 546 -- --------------------------------------------------------------------------- 547 -- Generic separators 548 -- 549 -- `lines`, `unlines`, `words` and `unwords` at the bottom of this section are 550 -- the byte-valued special cases of these primitives. 551 -- 552 -- Joining takes any separator; splitting takes one byte. Separators are removed 553 -- rather than kept, and empty fields are preserved. 554 -- --------------------------------------------------------------------------- 555 556 takeWhile f xs = (let rec 557 walk remaining = (lazyList 558 (_ : t) 559 (h r : case f h of 560 t = t 561 _ = pair h (walk r)) 562 remaining) 563 in walk xs) 564 565 dropWhile f xs = (let rec 566 walk remaining = (lazyList 567 (_ : t) 568 (h r : case f h of 569 t = pair h r 570 _ = walk r) 571 remaining) 572 in walk xs) 573 574 -- Byte-level whitespace only: space and horizontal tab (HTTP OWS). 575 spaceByte? = b : equal? b 32 576 tabByte? = b : equal? b 9 577 trimByte? = b : or? (spaceByte? b) (tabByte? b) 578 579 trim = xs : dropWhile trimByte? (reverse (dropWhile trimByte? (reverse xs))) 580 581 intercalate sep xs = (let rec 582 walk remaining = (lazyList 583 (_ : t) 584 (h r : case emptyList? r of 585 t = append h (append sep (walk r)) 586 _ = h) 587 remaining) 588 in walk xs) 589 590 -- Separator after every field, including the last one. Line-oriented formats 591 -- want this: `joinSuffix "\n" xs` terminates the final line while 592 -- `intercalate "\n" xs` does not. 593 joinSuffix sep xs = (let rec 594 walk remaining = (lazyList 595 (_ : t) 596 (h r : append (append h sep) (walk r)) 597 remaining) 598 in walk xs) 599 600 -- Split on a single byte. 601 -- Empty fields are preserved: `splitOnByte 58 "a::b"` is ["a" "" "b"]. 602 -- Keep the two small thunks here: case dispatch and extra local branch 603 -- bindings both add measurable per-byte costs in the splitter. 604 splitOnByte byte str = (let rec 605 walk remaining reversedFields reversedField = (lazyList 606 (_ : map reverse (reverse (pair reversedField reversedFields))) 607 (h r : lazyBool 608 (_ : walk r (pair reversedField reversedFields) t) 609 (_ : walk r reversedFields (pair h reversedField)) 610 (equal? h byte)) 611 remaining) 612 in walk str t t) 613 614 -- Every one of these keeps its arguments bound: partially applying a 615 -- multi-argument function at the top level leaves a fixed point exposed. 616 lines = str : splitOnByte 10 str 617 unlines = xs : joinSuffix "\n" xs 618 619 -- Runs of separators collapse: empty fields are dropped. 620 words = str : filter (w : not? (emptyList? w)) (splitOnByte 32 str) 621 unwords = xs : intercalate " " xs 622 623 zipWith_ self f xs ys = 624 matchList 625 t 626 (xh xt : 627 matchList 628 t 629 (yh yt : pair (f xh yh) (self f xt yt)) 630 ys) 631 xs 632 zipWith = f xs ys : y zipWith_ f xs ys 633 634 -- --------------------------------------------------------------------------- 635 -- Core contract type 636 -- 637 -- A contract is an ordinary tricu function: Tree -> Tree -> Result Tree Tree. 638 -- The second argument is the conventional "rest" slot. On success a contract 639 -- returns the checked value wrapped in the standard ok shape; on failure it 640 -- returns a diagnostic wrapped in the standard err shape. 641 -- 642 -- The contract kernel is a globally configurable function selected by the 643 -- runner. It decides whether to accept the contract result, replace it, log 644 -- it, or transform the diagnostic. The default kernel is the identity on the 645 -- contract Result. 646 -- 647 -- The runner may rebind 'kernel' to a different kernel before evaluating 648 -- user code (e.g. via --contract-kernel). 649 -- --------------------------------------------------------------------------- 650 651 contractOk = (value : (rest : ok value rest)) 652 contractErr = (msg : (rest : err msg rest)) 653 654 -- Default contract kernel. Return the contract Result unchanged. 655 defaultKernel = (contract value result : 656 matchResult 657 (msg rest : err msg rest) 658 (v rest : ok v rest) 659 result) 660 661 -- The active kernel. The runner may rebind this name to a different kernel 662 -- before evaluating user code (e.g. via --contract-kernel). Internally, 663 -- withContract dispatches through this binding, so rebinding 'kernel' changes 664 -- the behaviour of every contract boundary in the program. 665 kernel = defaultKernel 666 667 -- Skip-everything kernel. Resume with the original value on failure. 668 skipKernel = (contract value result : 669 matchResult 670 (msg rest : ok value rest) 671 (v rest : ok v rest) 672 result) 673 674 -- Apply a contract and pass the raw Result to the kernel. 675 withContract = (contract value : 676 kernel contract value (contract value t)) 677 678 -- Apply a contract and return the checked value or the diagnostic message. 679 check contract value = 680 matchResult 681 (msg _ : msg) 682 (v _ : v) 683 (withContract contract value) 684 685 -- Apply a contract and return the raw Result (kernel is bypassed). 686 checkContract = (contract value : contract value t) 687 688 -- --------------------------------------------------------------------------- 689 -- Basic contracts 690 -- --------------------------------------------------------------------------- 691 692 -- Any value passes. 693 anyC = (value : contractOk value) 694 695 -- Always fails with the supplied message. 696 neverC = (msg : (value : contractErr msg)) 697 698 -- Build a contract from a predicate that inspects only the value. 699 guardC msg predicate value rest = case predicate value of 700 t = contractErr msg rest 701 _ = contractOk value rest 702 703 -- Structural natural-number predicate. 704 -- A natural is either Leaf (0) or Fork bit rest where bit is Leaf (even) 705 -- or Stem Leaf (odd) and rest is itself a natural. 706 isNat? = y (self n : 707 triage 708 true 709 (_ : false) 710 (bit r : 711 triage 712 (self r) 713 (_ : self r) 714 (_ _ : false) 715 bit) 716 n) 717 718 -- Natural number contract. 719 nat? = guardC "not a natural number" isNat? 720 721 -- Non-zero natural number contract. 722 nonZero? = guardC "non-zero" (n : and? (isNat? n) (not? (isZero_? n))) 723 724 -- Boolean contract. 725 bool? = guardC "not a boolean" (b : or? (equal? b true) (equal? b false)) 726 727 -- --------------------------------------------------------------------------- 728 -- Contract combinators 729 -- --------------------------------------------------------------------------- 730 731 andC = (c1 c2 value rest : 732 matchResult 733 (msg _ : contractErr msg rest) 734 (v _ : c2 v rest) 735 (c1 value rest)) 736 737 orC = (c1 c2 value rest : 738 matchResult 739 (msg _ : c2 value rest) 740 (v _ : contractOk v rest) 741 (c1 value rest)) 742 743 notC = (c value rest : 744 matchResult 745 (msg _ : contractOk value rest) 746 (_ _ : contractErr "notC: predicate succeeded" rest) 747 (c value rest)) 748 749 mapC = (f c value rest : 750 matchResult 751 (msg _ : contractErr msg rest) 752 (v _ : contractOk (f v) rest) 753 (c value rest)) 754 755 bindC = (c f value rest : 756 matchResult 757 (msg _ : contractErr msg rest) 758 (v _ : f v value rest) 759 (c value rest)) 760 761 -- --------------------------------------------------------------------------- 762 -- Collection contracts 763 -- --------------------------------------------------------------------------- 764 765 listOf = (c value rest : 766 y (self orig xs : 767 matchList 768 (contractOk orig rest) 769 (h r : 770 matchResult 771 (msg _ : contractErr msg rest) 772 (_ _ : self orig r) 773 (c h rest)) 774 xs) value value) 775 776 nonEmptyListOf = (c : 777 andC (guardC "empty list" (xs : not? (emptyList? xs))) (listOf c)) 778 779 pairOf = (c1 c2 p rest : 780 matchPair 781 (a b : 782 matchResult 783 (msg _ : contractErr msg rest) 784 (a' _ : 785 matchResult 786 (msg _ : contractErr msg rest) 787 (b' _ : contractOk (pair a' b') rest) 788 (c2 b rest)) 789 (c1 a rest)) 790 p) 791 792 -- --------------------------------------------------------------------------- 793 -- Higher-order function contracts 794 -- 795 -- These return a Result-wrapped proxy. The proxy itself is a contract: it 796 -- checks arguments on the way in and results on the way out. 797 -- --------------------------------------------------------------------------- 798 799 fnContract = (argC resC f rest : 800 contractOk 801 (x : (rest1 : 802 matchResult 803 (msg _ : contractErr msg rest1) 804 (x' _ : 805 matchResult 806 (msg _ : contractErr msg rest1) 807 (y _ : contractOk y rest1) 808 (withContract resC (f x'))) 809 (withContract argC x))) 810 rest) 811 812 fn2 = (arg1C arg2C resC f rest : 813 contractOk 814 (x : (rest1 : 815 matchResult 816 (msg _ : contractErr msg rest1) 817 (x' _ : 818 contractOk 819 (y : (rest2 : 820 matchResult 821 (msg _ : contractErr msg rest2) 822 (y' _ : 823 matchResult 824 (msg _ : contractErr msg rest2) 825 (z _ : contractOk z rest2) 826 (withContract resC (f x' y'))) 827 (withContract arg2C y))) 828 rest1) 829 (withContract arg1C x))) 830 rest) 831 832 -- --------------------------------------------------------------------------- 833 -- Interaction-tree effect layer 834 -- 835 -- These constructors and combinators layer catchable, composable failures on 836 -- top of the core Result contracts. They reuse the same tags as tricu IO: 837 -- 0 = pureE 838 -- 1 = bindE 839 -- 2 = exceptE 840 -- --------------------------------------------------------------------------- 841 842 pureE = (value : pair 0 value) 843 bindE = (action k : pair 1 (pair action k)) 844 exceptE = (tag value k : pair 2 (pair tag (pair value k))) 845 846 pureM = pureE 847 bindM = bindE 848 849 -- Lift a contract failure into an interaction tree. 850 checkM = (contract value : 851 matchResult 852 (msg _ : exceptE "contract" msg (_ : pureE t)) 853 (checked _ : pureE checked) 854 (contract value t)) 855 856 -- Lift a pure function into the interaction tree. 857 liftM = (f : (x : pureE (f x))) 858 859 -- Interpret a pure interaction tree into a Result. 860 runM tree = (matchPair interpret tree 861 where 862 interpret op payload = case op of 863 0 = contractOk payload t 864 1 = (matchPair 865 (action k : matchResult 866 (msg _ : contractErr msg t) 867 (value _ : runM (k value)) 868 (runM action)) 869 payload) 870 _ = (matchPair 871 (_ detail : matchPair (value _ : contractErr value t) detail) 872 payload)) 873 874 -- Handle matching exceptE nodes by applying the handler to the value and the 875 -- resumption continuation. Non-matching exceptions are left in place. 876 handleM tag handler tree = (let rec 877 handle current = (matchPair interpret current 878 where 879 choose exceptionTag value k = case equal? exceptionTag tag of 880 t = current 881 _ = handle (handler value k) 882 handleException exceptionTag detail = matchPair (choose exceptionTag) detail 883 interpret op payload = case op of 884 0 = current 885 1 = (matchPair 886 (action k : bindE (handle action) (value : handle (k value))) 887 payload) 888 _ = matchPair handleException payload) 889 in handle tree)