|
| 1 | +(package coalton-library/classes |
| 2 | + (import |
| 3 | + (coalton-library/types as types)) |
| 4 | + (export |
| 5 | + Signalable |
| 6 | + error |
| 7 | + Tuple |
| 8 | + Optional Some None |
| 9 | + Result Ok Err |
| 10 | + Eq == |
| 11 | + Ord LT EQ GT |
| 12 | + <=> > < >= <= |
| 13 | + max |
| 14 | + min |
| 15 | + Num + - * fromInt |
| 16 | + Semigroup <> |
| 17 | + Monoid mempty |
| 18 | + Functor map |
| 19 | + Applicative pure liftA2 |
| 20 | + Monad >>= |
| 21 | + >> |
| 22 | + MonadFail fail |
| 23 | + Alternative alt empty |
| 24 | + Foldable fold foldr mconcat |
| 25 | + Traversable traverse |
| 26 | + Bifunctor bimap map-fst map-snd |
| 27 | + sequence |
| 28 | + Into |
| 29 | + TryInto |
| 30 | + Iso |
| 31 | + Unwrappable unwrap-or-else with-default unwrap expect as-optional |
| 32 | + default defaulting-unwrap default?)) |
| 33 | + |
| 34 | +;;; |
| 35 | +;;; Signaling errors and warnings |
| 36 | +;;; |
| 37 | + |
| 38 | +;; |
| 39 | +;; Signalling errors on supported types |
| 40 | +;; |
| 41 | +(define-class (Signalable :a) |
| 42 | + "Signals errors or warnings by calling their respective lisp conditions." |
| 43 | + (error "Signal an error with a type-specific error string." (:a -> :b))) |
| 44 | + |
| 45 | +(define-instance (Signalable String) |
| 46 | + (define (error str) |
| 47 | + (lisp :a (str) |
| 48 | + (cl:error str)))) |
| 49 | + |
| 50 | +;; |
| 51 | +;; Base Types |
| 52 | +;; |
| 53 | + |
| 54 | +(define-struct (Tuple :a :b) |
| 55 | + "A heterogeneous collection of items." |
| 56 | + (first :a) |
| 57 | + (second :b)) |
| 58 | + |
| 59 | +(define-type (Optional :a) |
| 60 | + "Represents something that may not have a value." |
| 61 | + (Some :a) |
| 62 | + None) |
| 63 | + |
| 64 | +(define-type (Result :bad :good) |
| 65 | + "Represents something that may have failed." |
| 66 | + ;; We write (Result :bad :good) instead of (Result :good :bad) |
| 67 | + ;; because of the limitations of how we deal with higher-kinded |
| 68 | + ;; types; we want to implement Functor on this. |
| 69 | + (Ok :good) |
| 70 | + (Err :bad)) |
| 71 | + |
| 72 | +;; |
| 73 | +;; Eq |
| 74 | +;; |
| 75 | + |
| 76 | +(define-class (Eq :a) |
| 77 | + "Types which have equality defined." |
| 78 | + (== (:a -> :a -> Boolean))) |
| 79 | + |
| 80 | +(define-instance (Eq types:LispType) |
| 81 | + (define (== a b) |
| 82 | + (lisp Boolean (a b) |
| 83 | + (cl:equalp a b)))) |
| 84 | + |
| 85 | +(define-class (Eq :a => Num :a) |
| 86 | + "Types which have numeric operations defined." |
| 87 | + (+ (:a -> :a -> :a)) |
| 88 | + (- (:a -> :a -> :a)) |
| 89 | + (* (:a -> :a -> :a)) |
| 90 | + (fromInt (Integer -> :a))) |
| 91 | + |
| 92 | +(define-instance (Eq Unit) |
| 93 | + (define (== _ _) True)) |
| 94 | + |
| 95 | +;; |
| 96 | +;; Ord |
| 97 | +;; |
| 98 | + |
| 99 | +(repr :enum) |
| 100 | +(define-type Ord |
| 101 | + "The result of an ordered comparison." |
| 102 | + LT |
| 103 | + EQ |
| 104 | + GT) |
| 105 | + |
| 106 | +(define-instance (Eq Ord) |
| 107 | + (define (== a b) |
| 108 | + (match (Tuple a b) |
| 109 | + ((Tuple (LT) (LT)) True) |
| 110 | + ((Tuple (EQ) (EQ)) True) |
| 111 | + ((Tuple (GT) (GT)) True) |
| 112 | + (_ False)))) |
| 113 | + |
| 114 | +(define-instance (Ord Ord) |
| 115 | + (define (<=> a b) |
| 116 | + (match (Tuple a b) |
| 117 | + ((Tuple (LT) (LT)) EQ) |
| 118 | + ((Tuple (LT) (EQ)) LT) |
| 119 | + ((Tuple (LT) (GT)) LT) |
| 120 | + ((Tuple (EQ) (LT)) GT) |
| 121 | + ((Tuple (EQ) (EQ)) EQ) |
| 122 | + ((Tuple (EQ) (GT)) LT) |
| 123 | + ((Tuple (GT) (LT)) GT) |
| 124 | + ((Tuple (GT) (EQ)) GT) |
| 125 | + ((Tuple (GT) (GT)) EQ)))) |
| 126 | + |
| 127 | +(define-class (Eq :a => Ord :a) |
| 128 | + "Types whose values can be ordered." |
| 129 | + (<=> (:a -> :a -> Ord))) |
| 130 | + |
| 131 | +(declare > (Ord :a => :a -> :a -> Boolean)) |
| 132 | +(define (> x y) |
| 133 | + "Is `x` greater than `y`?" |
| 134 | + (match (<=> x y) |
| 135 | + ((GT) True) |
| 136 | + (_ False))) |
| 137 | + |
| 138 | +(declare < (Ord :a => :a -> :a -> Boolean)) |
| 139 | +(define (< x y) |
| 140 | + "Is `x` less than `y`?" |
| 141 | + (match (<=> x y) |
| 142 | + ((LT) True) |
| 143 | + (_ False))) |
| 144 | + |
| 145 | +(declare >= (Ord :a => :a -> :a -> Boolean)) |
| 146 | +(define (>= x y) |
| 147 | + "Is `x` greater than or equal to `y`?" |
| 148 | + (match (<=> x y) |
| 149 | + ((LT) False) |
| 150 | + (_ True))) |
| 151 | + |
| 152 | +(declare <= (Ord :a => :a -> :a -> Boolean)) |
| 153 | +(define (<= x y) |
| 154 | + "Is `x` less than or equal to `y`?" |
| 155 | + (match (<=> x y) |
| 156 | + ((GT) False) |
| 157 | + (_ True))) |
| 158 | + |
| 159 | +(declare max (Ord :a => :a -> :a -> :a)) |
| 160 | +(define (max x y) |
| 161 | + "Returns the greater element of `x` and `y`." |
| 162 | + (if (> x y) |
| 163 | + x |
| 164 | + y)) |
| 165 | + |
| 166 | +(declare min (Ord :a => :a -> :a -> :a)) |
| 167 | +(define (min x y) |
| 168 | + "Returns the lesser element of `x` and `y`." |
| 169 | + (if (< x y) |
| 170 | + x |
| 171 | + y)) |
| 172 | + |
| 173 | + ;; |
| 174 | + ;; Haskell |
| 175 | + ;; |
| 176 | + |
| 177 | +(define-class (Semigroup :a) |
| 178 | + "Types with an associative binary operation defined." |
| 179 | + (<> (:a -> :a -> :a))) |
| 180 | + |
| 181 | +(define-class (Semigroup :a => Monoid :a) |
| 182 | + "Types with an associative binary operation and identity defined." |
| 183 | + (mempty :a)) |
| 184 | + |
| 185 | +(define-class (Functor :f) |
| 186 | + "Types which can map an inner type where the mapping adheres to the identity and composition laws." |
| 187 | + (map ((:a -> :b) -> :f :a -> :f :b))) |
| 188 | + |
| 189 | +(define-class (Functor :f => Applicative :f) |
| 190 | + "Types which are a functor which can embed pure expressions and sequence operations." |
| 191 | + (pure (:a -> (:f :a))) |
| 192 | + (liftA2 ((:a -> :b -> :c) -> :f :a -> :f :b -> :f :c))) |
| 193 | + |
| 194 | +(define-class (Applicative :m => Monad :m) |
| 195 | + "Types which are monads as defined in Haskell. See https://wiki.haskell.org/Monad for more information." |
| 196 | + (>>= (:m :a -> (:a -> :m :b) -> :m :b))) |
| 197 | + |
| 198 | +(declare >> (Monad :m => (:m :a) -> (:m :b) -> (:m :b))) |
| 199 | +(define (>> a b) |
| 200 | + (>>= a (fn (_) b))) |
| 201 | + |
| 202 | +(define-class (Monad :m => MonadFail :m) |
| 203 | + (fail (String -> :m :a))) |
| 204 | + |
| 205 | +(define-class (Applicative :f => Alternative :f) |
| 206 | + "Types which are monoids on applicative functors." |
| 207 | + (alt (:f :a -> :f :a -> :f :a)) |
| 208 | + (empty (:f :a))) |
| 209 | + |
| 210 | +(define-class (Foldable :container) |
| 211 | + "Types which can be folded into a single element." |
| 212 | + (fold "A left tail-recursive fold." ((:accum -> :elt -> :accum) -> :accum -> :container :elt -> :accum)) |
| 213 | + (foldr "A right non-tail-recursive fold."((:elt -> :accum -> :accum) -> :accum -> :container :elt -> :accum))) |
| 214 | + |
| 215 | +(declare mconcat ((Foldable :f) (Monoid :a) => :f :a -> :a)) |
| 216 | +(define mconcat |
| 217 | + "Fold a container of monoids into a single element." |
| 218 | + (fold <> mempty)) |
| 219 | + |
| 220 | +(define-class (Traversable :t) |
| 221 | + (traverse (Applicative :f => (:a -> :f :b) -> :t :a -> :f (:t :b)))) |
| 222 | + |
| 223 | +(declare sequence ((Traversable :t) (Applicative :f) => :t (:f :b) -> :f (:t :b))) |
| 224 | +(define sequence (traverse (fn (x) x))) |
| 225 | + |
| 226 | +(define-class (Bifunctor :f) |
| 227 | + "Types which take two type arguments and are functors on both." |
| 228 | + (bimap ((:a -> :b) -> (:c -> :d) -> :f :a :c -> :f :b :d))) |
| 229 | + |
| 230 | +(declare map-fst (Bifunctor :f => (:a -> :b) -> :f :a :c -> :f :b :c)) |
| 231 | +(define (map-fst f b) |
| 232 | + "Map over the first argument of a `Bifunctor`." |
| 233 | + (bimap f (fn (x) x) b)) |
| 234 | + |
| 235 | +(declare map-snd (Bifunctor :f => (:b -> :c) -> :f :a :b -> :f :a :c)) |
| 236 | +(define (map-snd f b) |
| 237 | + "Map over the second argument of a `Bifunctor`." |
| 238 | + (bimap (fn (x) x) f b)) |
| 239 | + |
| 240 | + ;; |
| 241 | + ;; Conversions |
| 242 | + ;; |
| 243 | + |
| 244 | +(define-class (Into :a :b) |
| 245 | + "`INTO` imples *every* element of `:a` can be represented by an element of `:b`. This conversion might not be bijective (i.e., there may be elements in `:b` that don't correspond to any in `:a`)." |
| 246 | + (into (:a -> :b))) |
| 247 | + |
| 248 | +(define-class ((Into :a :b) (Into :b :a) => Iso :a :b) |
| 249 | + "Opting into this marker typeclass imples that the instances for `(Into :a :b)` and `(Into :b :a)` form a bijection.") |
| 250 | + |
| 251 | +(define-instance (Into :a :a) |
| 252 | + (define (into x) x)) |
| 253 | + |
| 254 | +(define-class (TryInto :a :b :c (:a :b -> :c)) |
| 255 | + "`TRY-INTO` implies some elements of `:a` can be represented exactly by an element of `:b`, but sometimes not. If not, an error of type `:c` is returned." |
| 256 | + (tryInto (:a -> (Result :c :b)))) |
| 257 | + |
| 258 | +(define-instance (Iso :a :a)) |
| 259 | + |
| 260 | + ;; |
| 261 | + ;; Unwrappable for fallible unboxing |
| 262 | + ;; |
| 263 | + |
| 264 | +(define-class (Unwrappable :container) |
| 265 | + "Containers which can be unwrapped to get access to their contents. |
| 266 | + |
| 267 | +`(unwrap-or-else succeed fail container)` should invoke the `succeed` continuation on the unwrapped contents of |
| 268 | +`container` when successful, or invoke the `fail` continuation with no arguments (i.e., with `Unit` as an argument) |
| 269 | +when unable to unwrap a value. |
| 270 | + |
| 271 | +The `succeed` continuation will often, but not always, be the identity function. `as-optional` passes `Some` to |
| 272 | +construct an `Optional`. |
| 273 | + |
| 274 | +Typical `fail` continuations are: |
| 275 | +- Return a default value, or |
| 276 | +- Signal an error." |
| 277 | + (unwrap-or-else ((:elt -> :result) |
| 278 | + -> (Unit -> :result) |
| 279 | + -> (:container :elt) |
| 280 | + -> :result))) |
| 281 | + |
| 282 | +(declare expect ((Unwrappable :container) => |
| 283 | + String |
| 284 | + -> (:container :element) |
| 285 | + -> :element)) |
| 286 | +(define (expect reason container) |
| 287 | + "Unwrap `container`, signaling an error with the description `reason` on failure." |
| 288 | + (unwrap-or-else (fn (elt) elt) |
| 289 | + (fn () (error reason)) |
| 290 | + container)) |
| 291 | + |
| 292 | +(declare unwrap ((Unwrappable :container) => |
| 293 | + (:container :element) |
| 294 | + -> :element)) |
| 295 | +(define (unwrap container) |
| 296 | + "Unwrap `container`, signaling an error on failure." |
| 297 | + (unwrap-or-else (fn (elt) elt) |
| 298 | + (fn () (error (lisp String (container) |
| 299 | + (cl:format cl:nil "Unexpected ~a in UNWRAP" |
| 300 | + container)))) |
| 301 | + container)) |
| 302 | + |
| 303 | +(declare with-default ((Unwrappable :container) => |
| 304 | + :element |
| 305 | + -> (:container :element) |
| 306 | + -> :element)) |
| 307 | +(define (with-default default container) |
| 308 | + "Unwrap `container`, returning `default` on failure." |
| 309 | + (unwrap-or-else (fn (elt) elt) |
| 310 | + (fn () default) |
| 311 | + container)) |
| 312 | + |
| 313 | +(declare as-optional ((Unwrappable :container) => (:container :elt) -> (Optional :elt))) |
| 314 | +(define (as-optional container) |
| 315 | + "Convert any Unwrappable container into an `Optional`, constructing Some on a successful unwrap and None on a failed unwrap." |
| 316 | + (unwrap-or-else Some |
| 317 | + (fn () None) |
| 318 | + container)) |
| 319 | + |
| 320 | + |
| 321 | + ;; |
| 322 | + ;; Default |
| 323 | + ;; |
| 324 | + |
| 325 | +(define-class (Default :a) |
| 326 | + "Types which have default values." |
| 327 | + (default (Unit -> :a))) |
| 328 | + |
| 329 | +(declare defaulting-unwrap ((Unwrappable :container) (Default :element) => |
| 330 | + (:container :element) -> :element)) |
| 331 | +(define (defaulting-unwrap container) |
| 332 | + "Unwrap an `unwrappable`, returning `(default)` of the wrapped type on failure. " |
| 333 | + (unwrap-or-else (fn (elt) elt) |
| 334 | + (fn () (default)) |
| 335 | + container)) |
| 336 | + |
| 337 | +(declare default? ((Default :a) (Eq :a) => :a -> Boolean)) |
| 338 | +(define (default? x) |
| 339 | + "Is `x` the default item of its type?" |
| 340 | + (== x (default))) |
0 commit comments