8 Type classes were introduced by Wadler and Blott @{cite wadler89how} |
8 Type classes were introduced by Wadler and Blott @{cite wadler89how} |
9 into the Haskell language to allow for a reasonable implementation |
9 into the Haskell language to allow for a reasonable implementation |
10 of overloading\footnote{throughout this tutorial, we are referring |
10 of overloading\footnote{throughout this tutorial, we are referring |
11 to classical Haskell 1.0 type classes, not considering later |
11 to classical Haskell 1.0 type classes, not considering later |
12 additions in expressiveness}. As a canonical example, a polymorphic |
12 additions in expressiveness}. As a canonical example, a polymorphic |
13 equality function @{text "eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} which is overloaded on |
13 equality function \<open>eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool\<close> which is overloaded on |
14 different types for @{text "\<alpha>"}, which is achieved by splitting |
14 different types for \<open>\<alpha>\<close>, which is achieved by splitting |
15 introduction of the @{text eq} function from its overloaded |
15 introduction of the \<open>eq\<close> function from its overloaded |
16 definitions by means of @{text class} and @{text instance} |
16 definitions by means of \<open>class\<close> and \<open>instance\<close> |
17 declarations: \footnote{syntax here is a kind of isabellized |
17 declarations: \footnote{syntax here is a kind of isabellized |
18 Haskell} |
18 Haskell} |
19 |
19 |
20 \begin{quote} |
20 \begin{quote} |
21 |
21 |
22 \<^noindent> @{text "class eq where"} \\ |
22 \<^noindent> \<open>class eq where\<close> \\ |
23 \hspace*{2ex}@{text "eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} |
23 \hspace*{2ex}\<open>eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool\<close> |
24 |
24 |
25 \<^medskip>\<^noindent> @{text "instance nat :: eq where"} \\ |
25 \<^medskip>\<^noindent> \<open>instance nat :: eq where\<close> \\ |
26 \hspace*{2ex}@{text "eq 0 0 = True"} \\ |
26 \hspace*{2ex}\<open>eq 0 0 = True\<close> \\ |
27 \hspace*{2ex}@{text "eq 0 _ = False"} \\ |
27 \hspace*{2ex}\<open>eq 0 _ = False\<close> \\ |
28 \hspace*{2ex}@{text "eq _ 0 = False"} \\ |
28 \hspace*{2ex}\<open>eq _ 0 = False\<close> \\ |
29 \hspace*{2ex}@{text "eq (Suc n) (Suc m) = eq n m"} |
29 \hspace*{2ex}\<open>eq (Suc n) (Suc m) = eq n m\<close> |
30 |
30 |
31 \<^medskip>\<^noindent> @{text "instance (\<alpha>::eq, \<beta>::eq) pair :: eq where"} \\ |
31 \<^medskip>\<^noindent> \<open>instance (\<alpha>::eq, \<beta>::eq) pair :: eq where\<close> \\ |
32 \hspace*{2ex}@{text "eq (x1, y1) (x2, y2) = eq x1 x2 \<and> eq y1 y2"} |
32 \hspace*{2ex}\<open>eq (x1, y1) (x2, y2) = eq x1 x2 \<and> eq y1 y2\<close> |
33 |
33 |
34 \<^medskip>\<^noindent> @{text "class ord extends eq where"} \\ |
34 \<^medskip>\<^noindent> \<open>class ord extends eq where\<close> \\ |
35 \hspace*{2ex}@{text "less_eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} \\ |
35 \hspace*{2ex}\<open>less_eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool\<close> \\ |
36 \hspace*{2ex}@{text "less :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} |
36 \hspace*{2ex}\<open>less :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool\<close> |
37 |
37 |
38 \end{quote} |
38 \end{quote} |
39 |
39 |
40 \<^noindent> Type variables are annotated with (finitely many) classes; |
40 \<^noindent> Type variables are annotated with (finitely many) classes; |
41 these annotations are assertions that a particular polymorphic type |
41 these annotations are assertions that a particular polymorphic type |
47 |
47 |
48 From a software engineering point of view, type classes roughly |
48 From a software engineering point of view, type classes roughly |
49 correspond to interfaces in object-oriented languages like Java; so, |
49 correspond to interfaces in object-oriented languages like Java; so, |
50 it is naturally desirable that type classes do not only provide |
50 it is naturally desirable that type classes do not only provide |
51 functions (class parameters) but also state specifications |
51 functions (class parameters) but also state specifications |
52 implementations must obey. For example, the @{text "class eq"} |
52 implementations must obey. For example, the \<open>class eq\<close> |
53 above could be given the following specification, demanding that |
53 above could be given the following specification, demanding that |
54 @{text "class eq"} is an equivalence relation obeying reflexivity, |
54 \<open>class eq\<close> is an equivalence relation obeying reflexivity, |
55 symmetry and transitivity: |
55 symmetry and transitivity: |
56 |
56 |
57 \begin{quote} |
57 \begin{quote} |
58 |
58 |
59 \<^noindent> @{text "class eq where"} \\ |
59 \<^noindent> \<open>class eq where\<close> \\ |
60 \hspace*{2ex}@{text "eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} \\ |
60 \hspace*{2ex}\<open>eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool\<close> \\ |
61 @{text "satisfying"} \\ |
61 \<open>satisfying\<close> \\ |
62 \hspace*{2ex}@{text "refl: eq x x"} \\ |
62 \hspace*{2ex}\<open>refl: eq x x\<close> \\ |
63 \hspace*{2ex}@{text "sym: eq x y \<longleftrightarrow> eq x y"} \\ |
63 \hspace*{2ex}\<open>sym: eq x y \<longleftrightarrow> eq x y\<close> \\ |
64 \hspace*{2ex}@{text "trans: eq x y \<and> eq y z \<longrightarrow> eq x z"} |
64 \hspace*{2ex}\<open>trans: eq x y \<and> eq y z \<longrightarrow> eq x z\<close> |
65 |
65 |
66 \end{quote} |
66 \end{quote} |
67 |
67 |
68 \<^noindent> From a theoretical point of view, type classes are |
68 \<^noindent> From a theoretical point of view, type classes are |
69 lightweight modules; Haskell type classes may be emulated by SML |
69 lightweight modules; Haskell type classes may be emulated by SML |
204 |
202 |
205 end %quote |
203 end %quote |
206 |
204 |
207 text \<open> |
205 text \<open> |
208 \<^noindent> Associativity of product semigroups is established using |
206 \<^noindent> Associativity of product semigroups is established using |
209 the definition of @{text "(\<otimes>)"} on products and the hypothetical |
207 the definition of \<open>(\<otimes>)\<close> on products and the hypothetical |
210 associativity of the type components; these hypotheses are |
208 associativity of the type components; these hypotheses are |
211 legitimate due to the @{class semigroup} constraints imposed on the |
209 legitimate due to the @{class semigroup} constraints imposed on the |
212 type components by the @{command instance} proposition. Indeed, |
210 type components by the @{command instance} proposition. Indeed, |
213 this pattern often occurs with parametric types and type classes. |
211 this pattern often occurs with parametric types and type classes. |
214 \<close> |
212 \<close> |
215 |
213 |
216 |
214 |
217 subsection \<open>Subclassing\<close> |
215 subsection \<open>Subclassing\<close> |
218 |
216 |
219 text \<open> |
217 text \<open> |
220 We define a subclass @{text monoidl} (a semigroup with a left-hand |
218 We define a subclass \<open>monoidl\<close> (a semigroup with a left-hand |
221 neutral) by extending @{class semigroup} with one additional |
219 neutral) by extending @{class semigroup} with one additional |
222 parameter @{text neutral} together with its characteristic property: |
220 parameter \<open>neutral\<close> together with its characteristic property: |
223 \<close> |
221 \<close> |
224 |
222 |
225 class %quote monoidl = semigroup + |
223 class %quote monoidl = semigroup + |
226 fixes neutral :: "\<alpha>" ("\<one>") |
224 fixes neutral :: "\<alpha>" ("\<one>") |
227 assumes neutl: "\<one> \<otimes> x = x" |
225 assumes neutl: "\<one> \<otimes> x = x" |
354 |
351 |
355 consts %quote f :: "\<alpha> \<Rightarrow> \<alpha>" |
352 consts %quote f :: "\<alpha> \<Rightarrow> \<alpha>" |
356 |
353 |
357 text \<open> |
354 text \<open> |
358 \<^noindent> The connection to the type system is done by means of a |
355 \<^noindent> The connection to the type system is done by means of a |
359 primitive type class @{text "idem"}, together with a corresponding |
356 primitive type class \<open>idem\<close>, together with a corresponding |
360 interpretation: |
357 interpretation: |
361 \<close> |
358 \<close> |
362 |
359 |
363 interpretation %quote idem_class: |
360 interpretation %quote idem_class: |
364 idem "f :: (\<alpha>::idem) \<Rightarrow> \<alpha>" |
361 idem "f :: (\<alpha>::idem) \<Rightarrow> \<alpha>" |
365 (*<*)sorry(*>*) |
362 (*<*)sorry(*>*) |
366 |
363 |
367 text \<open> |
364 text \<open> |
368 \<^noindent> This gives you the full power of the Isabelle module system; |
365 \<^noindent> This gives you the full power of the Isabelle module system; |
369 conclusions in locale @{text idem} are implicitly propagated |
366 conclusions in locale \<open>idem\<close> are implicitly propagated |
370 to class @{text idem}. |
367 to class \<open>idem\<close>. |
371 \<close> (*<*)setup %invisible \<open>Sign.parent_path\<close> |
368 \<close> (*<*)setup %invisible \<open>Sign.parent_path\<close> |
372 (*>*) |
369 (*>*) |
373 subsection \<open>Abstract reasoning\<close> |
370 subsection \<open>Abstract reasoning\<close> |
374 |
371 |
375 text \<open> |
372 text \<open> |
376 Isabelle locales enable reasoning at a general level, while results |
373 Isabelle locales enable reasoning at a general level, while results |
377 are implicitly transferred to all instances. For example, we can |
374 are implicitly transferred to all instances. For example, we can |
378 now establish the @{text "left_cancel"} lemma for groups, which |
375 now establish the \<open>left_cancel\<close> lemma for groups, which |
379 states that the function @{text "(x \<otimes>)"} is injective: |
376 states that the function \<open>(x \<otimes>)\<close> is injective: |
380 \<close> |
377 \<close> |
381 |
378 |
382 lemma %quote (in group) left_cancel: "x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = z" |
379 lemma %quote (in group) left_cancel: "x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = z" |
383 proof |
380 proof |
384 assume "x \<otimes> y = x \<otimes> z" |
381 assume "x \<otimes> y = x \<otimes> z" |
393 text \<open> |
390 text \<open> |
394 \<^noindent> Here the \qt{@{keyword "in"} @{class group}} target |
391 \<^noindent> Here the \qt{@{keyword "in"} @{class group}} target |
395 specification indicates that the result is recorded within that |
392 specification indicates that the result is recorded within that |
396 context for later use. This local theorem is also lifted to the |
393 context for later use. This local theorem is also lifted to the |
397 global one @{fact "group.left_cancel:"} @{prop [source] "\<And>x y z :: |
394 global one @{fact "group.left_cancel:"} @{prop [source] "\<And>x y z :: |
398 \<alpha>::group. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = z"}. Since type @{text "int"} has been |
395 \<alpha>::group. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = z"}. Since type \<open>int\<close> has been |
399 made an instance of @{text "group"} before, we may refer to that |
396 made an instance of \<open>group\<close> before, we may refer to that |
400 fact as well: @{prop [source] "\<And>x y z :: int. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = |
397 fact as well: @{prop [source] "\<And>x y z :: int. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = |
401 z"}. |
398 z"}. |
402 \<close> |
399 \<close> |
403 |
400 |
404 |
401 |
433 programming; if we reconsider this in the context of what has been |
430 programming; if we reconsider this in the context of what has been |
434 said about type classes and locales, we can drive this analogy |
431 said about type classes and locales, we can drive this analogy |
435 further by stating that type classes essentially correspond to |
432 further by stating that type classes essentially correspond to |
436 functors that have a canonical interpretation as type classes. |
433 functors that have a canonical interpretation as type classes. |
437 There is also the possibility of other interpretations. For |
434 There is also the possibility of other interpretations. For |
438 example, @{text list}s also form a monoid with @{text append} and |
435 example, \<open>list\<close>s also form a monoid with \<open>append\<close> and |
439 @{term "[]"} as operations, but it seems inappropriate to apply to |
436 @{term "[]"} as operations, but it seems inappropriate to apply to |
440 lists the same operations as for genuinely algebraic types. In such |
437 lists the same operations as for genuinely algebraic types. In such |
441 a case, we can simply make a particular interpretation of monoids |
438 a case, we can simply make a particular interpretation of monoids |
442 for lists: |
439 for lists: |
443 \<close> |
440 \<close> |
470 qed intro_locales |
467 qed intro_locales |
471 |
468 |
472 text \<open> |
469 text \<open> |
473 \<^noindent> This pattern is also helpful to reuse abstract |
470 \<^noindent> This pattern is also helpful to reuse abstract |
474 specifications on the \emph{same} type. For example, think of a |
471 specifications on the \emph{same} type. For example, think of a |
475 class @{text preorder}; for type @{typ nat}, there are at least two |
472 class \<open>preorder\<close>; for type @{typ nat}, there are at least two |
476 possible instances: the natural order or the order induced by the |
473 possible instances: the natural order or the order induced by the |
477 divides relation. But only one of these instances can be used for |
474 divides relation. But only one of these instances can be used for |
478 @{command instantiation}; using the locale behind the class @{text |
475 @{command instantiation}; using the locale behind the class \<open>preorder\<close>, it is still possible to utilise the same abstract |
479 preorder}, it is still possible to utilise the same abstract |
|
480 specification again using @{command interpretation}. |
476 specification again using @{command interpretation}. |
481 \<close> |
477 \<close> |
482 |
478 |
483 subsection \<open>Additional subclass relations\<close> |
479 subsection \<open>Additional subclass relations\<close> |
484 |
480 |
485 text \<open> |
481 text \<open> |
486 Any @{text "group"} is also a @{text "monoid"}; this can be made |
482 Any \<open>group\<close> is also a \<open>monoid\<close>; this can be made |
487 explicit by claiming an additional subclass relation, together with |
483 explicit by claiming an additional subclass relation, together with |
488 a proof of the logical difference: |
484 a proof of the logical difference: |
489 \<close> |
485 \<close> |
490 |
486 |
491 subclass %quote (in group) monoid |
487 subclass %quote (in group) monoid |
496 with left_cancel show "x \<otimes> \<one> = x" by simp |
492 with left_cancel show "x \<otimes> \<one> = x" by simp |
497 qed |
493 qed |
498 |
494 |
499 text \<open> |
495 text \<open> |
500 The logical proof is carried out on the locale level. Afterwards it |
496 The logical proof is carried out on the locale level. Afterwards it |
501 is propagated to the type system, making @{text group} an instance |
497 is propagated to the type system, making \<open>group\<close> an instance |
502 of @{text monoid} by adding an additional edge to the graph of |
498 of \<open>monoid\<close> by adding an additional edge to the graph of |
503 subclass relations (\figref{fig:subclass}). |
499 subclass relations (\figref{fig:subclass}). |
504 |
500 |
505 \begin{figure}[htbp] |
501 \begin{figure}[htbp] |
506 \begin{center} |
502 \begin{center} |
507 \small |
503 \small |
508 \unitlength 0.6mm |
504 \unitlength 0.6mm |
509 \begin{picture}(40,60)(0,0) |
505 \begin{picture}(40,60)(0,0) |
510 \put(20,60){\makebox(0,0){@{text semigroup}}} |
506 \put(20,60){\makebox(0,0){\<open>semigroup\<close>}} |
511 \put(20,40){\makebox(0,0){@{text monoidl}}} |
507 \put(20,40){\makebox(0,0){\<open>monoidl\<close>}} |
512 \put(00,20){\makebox(0,0){@{text monoid}}} |
508 \put(00,20){\makebox(0,0){\<open>monoid\<close>}} |
513 \put(40,00){\makebox(0,0){@{text group}}} |
509 \put(40,00){\makebox(0,0){\<open>group\<close>}} |
514 \put(20,55){\vector(0,-1){10}} |
510 \put(20,55){\vector(0,-1){10}} |
515 \put(15,35){\vector(-1,-1){10}} |
511 \put(15,35){\vector(-1,-1){10}} |
516 \put(25,35){\vector(1,-3){10}} |
512 \put(25,35){\vector(1,-3){10}} |
517 \end{picture} |
513 \end{picture} |
518 \hspace{8em} |
514 \hspace{8em} |
519 \begin{picture}(40,60)(0,0) |
515 \begin{picture}(40,60)(0,0) |
520 \put(20,60){\makebox(0,0){@{text semigroup}}} |
516 \put(20,60){\makebox(0,0){\<open>semigroup\<close>}} |
521 \put(20,40){\makebox(0,0){@{text monoidl}}} |
517 \put(20,40){\makebox(0,0){\<open>monoidl\<close>}} |
522 \put(00,20){\makebox(0,0){@{text monoid}}} |
518 \put(00,20){\makebox(0,0){\<open>monoid\<close>}} |
523 \put(40,00){\makebox(0,0){@{text group}}} |
519 \put(40,00){\makebox(0,0){\<open>group\<close>}} |
524 \put(20,55){\vector(0,-1){10}} |
520 \put(20,55){\vector(0,-1){10}} |
525 \put(15,35){\vector(-1,-1){10}} |
521 \put(15,35){\vector(-1,-1){10}} |
526 \put(05,15){\vector(3,-1){30}} |
522 \put(05,15){\vector(3,-1){30}} |
527 \end{picture} |
523 \end{picture} |
528 \caption{Subclass relationship of monoids and groups: |
524 \caption{Subclass relationship of monoids and groups: |
529 before and after establishing the relationship |
525 before and after establishing the relationship |
530 @{text "group \<subseteq> monoid"}; transitive edges are left out.} |
526 \<open>group \<subseteq> monoid\<close>; transitive edges are left out.} |
531 \label{fig:subclass} |
527 \label{fig:subclass} |
532 \end{center} |
528 \end{center} |
533 \end{figure} |
529 \end{figure} |
534 |
530 |
535 For illustration, a derived definition in @{text group} using @{text |
531 For illustration, a derived definition in \<open>group\<close> using \<open>pow_nat\<close> |
536 pow_nat} |
|
537 \<close> |
532 \<close> |
538 |
533 |
539 definition %quote (in group) pow_int :: "int \<Rightarrow> \<alpha> \<Rightarrow> \<alpha>" where |
534 definition %quote (in group) pow_int :: "int \<Rightarrow> \<alpha> \<Rightarrow> \<alpha>" where |
540 "pow_int k x = (if k >= 0 |
535 "pow_int k x = (if k >= 0 |
541 then pow_nat (nat k) x |
536 then pow_nat (nat k) x |
565 |
560 |
566 term %quote "x \<otimes> y" \<comment> \<open>example 3\<close> |
561 term %quote "x \<otimes> y" \<comment> \<open>example 3\<close> |
567 |
562 |
568 text \<open> |
563 text \<open> |
569 \<^noindent> Here in example 1, the term refers to the local class |
564 \<^noindent> Here in example 1, the term refers to the local class |
570 operation @{text "mult [\<alpha>]"}, whereas in example 2 the type |
565 operation \<open>mult [\<alpha>]\<close>, whereas in example 2 the type |
571 constraint enforces the global class operation @{text "mult [nat]"}. |
566 constraint enforces the global class operation \<open>mult [nat]\<close>. |
572 In the global context in example 3, the reference is to the |
567 In the global context in example 3, the reference is to the |
573 polymorphic global class operation @{text "mult [?\<alpha> :: semigroup]"}. |
568 polymorphic global class operation \<open>mult [?\<alpha> :: semigroup]\<close>. |
574 \<close> |
569 \<close> |
575 |
570 |
576 section \<open>Further issues\<close> |
571 section \<open>Further issues\<close> |
577 |
572 |
578 subsection \<open>Type classes and code generation\<close> |
573 subsection \<open>Type classes and code generation\<close> |