secret
Created

  • Download Gist
try.rkt
Racket
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
#lang typed/racket/base
 
(provide
(struct-out Failure)
(struct-out Success)
failed succeded get invert
try-map try-flatmap try-foreach try-filter try-exists
rescue recover
try continue with-try)
 
(struct: (T) Failure ([exception : exn]))
 
(struct: (T) Success ([result : T]))
 
(define-type (Try T) (U (Failure T) (Success T)))
 
(: failed (All (T) (Try T) -> Boolean))
(define (failed try)
(Failure? try))
 
(: succeded (All (T) (Try T) -> Boolean))
(define (succeded try)
(Success? try))
 
(: get (All (T) (Try T) -> T))
(define (get try)
(cond
((Failure? try) (raise (Failure-exception try)))
((Success? try) (Success-result try))))
;; Is a generic "lens" library on structures possible??
;; Higher kinded types, L is a type constructor binding for M (Success) and N (Failure)
;; (: S-map (All (L T U) (L T) (T -> U) -> (L U)))
(: try-map (All (T U) (Try T) (T -> U) -> (Try U)))
(define (try-map try fn)
(cond
((Success? try)
(Success (fn (Success-result try))))
((Failure? try) try)))
 
(: try-flatmap (All (T U) (Try T) (T -> (Try U)) -> (Try U)))
(define (try-flatmap try fn)
(cond
((Success? try)
(with-handlers ([exn:fail? (λ: ((ex : exn))
(Failure ex))])
(fn (Success-result try))))
((Failure? try) try)))
 
(: try-foreach (All (T U) (Try T) (T -> U) -> Void))
(define (try-foreach try fn)
(cond
((Success? try)
(fn (Success-result try))
(void))
((Failure? try)
(void))))
 
(: try-filter (All (T) (Try T) (T -> Boolean) -> (Try T)))
(define (try-filter try select?)
(cond
((Success? try) ;; need to see of Racket has strutural pattern matching kindof cond!!!
(if (select? (Success-result try))
try
(Failure (exn:fail (format "Unsatisfied try filter predicate for ~s" (Success-result try))
(current-continuation-marks)))))
((Failure? try)
try)))
(: try-exists (All (T) (Try T) (T -> Boolean) -> Boolean))
(define (try-exists try exists?)
(cond
((Success? try)
(exists? (Success-result try)))
((Failure? try) #f)))
(: invert ((Try exn) -> (Try exn)))
(define (invert try)
(cond
((Success? try)
(Failure (exn:fail (format "Inverted try. Success for ~s is Failure" (Success-result try))
(current-continuation-marks))))
((Failure? try)
(Success (Failure-exception try)))))
 
 
(: continue (All (T V W) (Try T) (T -> (Try V)) (exn -> (Try W)) -> (Try (U V W))))
(define (continue try on-success on-failure)
(cond
((Success? try)
(on-success (Success-result try)))
((Failure? try)
(on-failure (Failure-exception try)))))
 
;; Rescue a failed computation if the rescue function is capable of doing so.
;; Careful of side effects by the rescue function.
;; Should my-hero be a PartialFunction as opposed to one which returns Option.
(: rescue (All (T) (Try T) ((Failure T) -> (Option (Try T))) -> (Try T)))
(define (rescue try my-hero)
(with-handlers ([exn:fail? (λ (ex)
(Failure ex))])
(cond
((Failure? try)
(let ((result (my-hero try)))
(if result
result
try)))
((Success? try) try))))
 
(: recover (All (T) (Try T) ((Failure T) -> (Option T)) -> (Try T)))
(define (recover try my-heroine)
(with-handlers ([exn:fail? (λ (ex)
(Failure ex))])
(cond
((Failure? try)
(let ((result (my-heroine try)))
(if result
(Success result)
try)))
((Success? try) try))))
 
(: try (All (T) (-> T) -> (Try T)))
(define (try thunk)
(with-handlers ([exn:fail? (lambda (ex)
(Failure ex))])
(Success (thunk))))
 
(define-syntax with-try
(syntax-rules ()
((_ body ...)
(try (lambda () body ...)))))

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.