Skip to content

Commit 7613436

Browse files
committed
classes.coal
1 parent 9e6b4cf commit 7613436

File tree

3 files changed

+341
-359
lines changed

3 files changed

+341
-359
lines changed

coalton.asd

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
(:file "utils")
4646
(:coalton-file "types")
4747
(:coalton-file "primitive-types")
48-
(:file "classes")
48+
(:coalton-file "classes")
4949
(:file "hash")
5050
(:file "builtin")
5151
(:coalton-file "functions")

library/classes.coal

+340
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
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

Comments
 (0)