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 \<Colon> \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} which is overloaded on |
13 equality function @{text "eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} which is overloaded on |
14 different types for @{text "\<alpha>"}, which is achieved by splitting |
14 different types for @{text "\<alpha>"}, which is achieved by splitting |
15 introduction of the @{text eq} function from its overloaded |
15 introduction of the @{text eq} function from its overloaded |
16 definitions by means of @{text class} and @{text instance} |
16 definitions by means of @{text class} and @{text instance} |
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@{text "class eq where"} \\ |
23 \hspace*{2ex}@{text "eq \<Colon> \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} |
23 \hspace*{2ex}@{text "eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} |
24 |
24 |
25 \medskip\noindent@{text "instance nat \<Colon> eq where"} \\ |
25 \medskip\noindent@{text "instance nat :: eq where"} \\ |
26 \hspace*{2ex}@{text "eq 0 0 = True"} \\ |
26 \hspace*{2ex}@{text "eq 0 0 = True"} \\ |
27 \hspace*{2ex}@{text "eq 0 _ = False"} \\ |
27 \hspace*{2ex}@{text "eq 0 _ = False"} \\ |
28 \hspace*{2ex}@{text "eq _ 0 = False"} \\ |
28 \hspace*{2ex}@{text "eq _ 0 = False"} \\ |
29 \hspace*{2ex}@{text "eq (Suc n) (Suc m) = eq n m"} |
29 \hspace*{2ex}@{text "eq (Suc n) (Suc m) = eq n m"} |
30 |
30 |
31 \medskip\noindent@{text "instance (\<alpha>\<Colon>eq, \<beta>\<Colon>eq) pair \<Colon> eq where"} \\ |
31 \medskip\noindent@{text "instance (\<alpha>::eq, \<beta>::eq) pair :: eq where"} \\ |
32 \hspace*{2ex}@{text "eq (x1, y1) (x2, y2) = eq x1 x2 \<and> eq y1 y2"} |
32 \hspace*{2ex}@{text "eq (x1, y1) (x2, y2) = eq x1 x2 \<and> eq y1 y2"} |
33 |
33 |
34 \medskip\noindent@{text "class ord extends eq where"} \\ |
34 \medskip\noindent@{text "class ord extends eq where"} \\ |
35 \hspace*{2ex}@{text "less_eq \<Colon> \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} \\ |
35 \hspace*{2ex}@{text "less_eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} \\ |
36 \hspace*{2ex}@{text "less \<Colon> \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} |
36 \hspace*{2ex}@{text "less :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} |
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 |
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@{text "class eq where"} \\ |
60 \hspace*{2ex}@{text "eq \<Colon> \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} \\ |
60 \hspace*{2ex}@{text "eq :: \<alpha> \<Rightarrow> \<alpha> \<Rightarrow> bool"} \\ |
61 @{text "satisfying"} \\ |
61 @{text "satisfying"} \\ |
62 \hspace*{2ex}@{text "refl: eq x x"} \\ |
62 \hspace*{2ex}@{text "refl: eq x x"} \\ |
63 \hspace*{2ex}@{text "sym: eq x y \<longleftrightarrow> eq x y"} \\ |
63 \hspace*{2ex}@{text "sym: eq x y \<longleftrightarrow> eq x y"} \\ |
64 \hspace*{2ex}@{text "trans: eq x y \<and> eq y z \<longrightarrow> eq x z"} |
64 \hspace*{2ex}@{text "trans: eq x y \<and> eq y z \<longrightarrow> eq x z"} |
65 |
65 |
109 \noindent This @{command class} specification consists of two parts: |
109 \noindent This @{command class} specification consists of two parts: |
110 the \qn{operational} part names the class parameter (@{element |
110 the \qn{operational} part names the class parameter (@{element |
111 "fixes"}), the \qn{logical} part specifies properties on them |
111 "fixes"}), the \qn{logical} part specifies properties on them |
112 (@{element "assumes"}). The local @{element "fixes"} and @{element |
112 (@{element "assumes"}). The local @{element "fixes"} and @{element |
113 "assumes"} are lifted to the theory toplevel, yielding the global |
113 "assumes"} are lifted to the theory toplevel, yielding the global |
114 parameter @{term [source] "mult \<Colon> \<alpha>\<Colon>semigroup \<Rightarrow> \<alpha> \<Rightarrow> \<alpha>"} and the |
114 parameter @{term [source] "mult :: \<alpha>::semigroup \<Rightarrow> \<alpha> \<Rightarrow> \<alpha>"} and the |
115 global theorem @{fact "semigroup.assoc:"}~@{prop [source] "\<And>x y z \<Colon> |
115 global theorem @{fact "semigroup.assoc:"}~@{prop [source] "\<And>x y z :: |
116 \<alpha>\<Colon>semigroup. (x \<otimes> y) \<otimes> z = x \<otimes> (y \<otimes> z)"}. |
116 \<alpha>::semigroup. (x \<otimes> y) \<otimes> z = x \<otimes> (y \<otimes> z)"}. |
117 *} |
117 *} |
118 |
118 |
119 |
119 |
120 subsection {* Class instantiation \label{sec:class_inst} *} |
120 subsection {* Class instantiation \label{sec:class_inst} *} |
121 |
121 |
195 |
195 |
196 definition %quote |
196 definition %quote |
197 mult_prod_def: "p\<^sub>1 \<otimes> p\<^sub>2 = (fst p\<^sub>1 \<otimes> fst p\<^sub>2, snd p\<^sub>1 \<otimes> snd p\<^sub>2)" |
197 mult_prod_def: "p\<^sub>1 \<otimes> p\<^sub>2 = (fst p\<^sub>1 \<otimes> fst p\<^sub>2, snd p\<^sub>1 \<otimes> snd p\<^sub>2)" |
198 |
198 |
199 instance %quote proof |
199 instance %quote proof |
200 fix p\<^sub>1 p\<^sub>2 p\<^sub>3 :: "\<alpha>\<Colon>semigroup \<times> \<beta>\<Colon>semigroup" |
200 fix p\<^sub>1 p\<^sub>2 p\<^sub>3 :: "\<alpha>::semigroup \<times> \<beta>::semigroup" |
201 show "p\<^sub>1 \<otimes> p\<^sub>2 \<otimes> p\<^sub>3 = p\<^sub>1 \<otimes> (p\<^sub>2 \<otimes> p\<^sub>3)" |
201 show "p\<^sub>1 \<otimes> p\<^sub>2 \<otimes> p\<^sub>3 = p\<^sub>1 \<otimes> (p\<^sub>2 \<otimes> p\<^sub>3)" |
202 unfolding mult_prod_def by (simp add: assoc) |
202 unfolding mult_prod_def by (simp add: assoc) |
203 qed |
203 qed |
204 |
204 |
205 end %quote |
205 end %quote |
392 |
392 |
393 text {* |
393 text {* |
394 \noindent Here the \qt{@{keyword "in"} @{class group}} target |
394 \noindent Here the \qt{@{keyword "in"} @{class group}} target |
395 specification indicates that the result is recorded within that |
395 specification indicates that the result is recorded within that |
396 context for later use. This local theorem is also lifted to the |
396 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 \<Colon> |
397 global one @{fact "group.left_cancel:"} @{prop [source] "\<And>x y z :: |
398 \<alpha>\<Colon>group. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = z"}. Since type @{text "int"} has been |
398 \<alpha>::group. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = z"}. Since type @{text "int"} has been |
399 made an instance of @{text "group"} before, we may refer to that |
399 made an instance of @{text "group"} before, we may refer to that |
400 fact as well: @{prop [source] "\<And>x y z \<Colon> int. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = |
400 fact as well: @{prop [source] "\<And>x y z :: int. x \<otimes> y = x \<otimes> z \<longleftrightarrow> y = |
401 z"}. |
401 z"}. |
402 *} |
402 *} |
403 |
403 |
404 |
404 |
405 subsection {* Derived definitions *} |
405 subsection {* Derived definitions *} |
413 | "pow_nat (Suc n) x = x \<otimes> pow_nat n x" |
413 | "pow_nat (Suc n) x = x \<otimes> pow_nat n x" |
414 |
414 |
415 text {* |
415 text {* |
416 \noindent If the locale @{text group} is also a class, this local |
416 \noindent If the locale @{text group} is also a class, this local |
417 definition is propagated onto a global definition of @{term [source] |
417 definition is propagated onto a global definition of @{term [source] |
418 "pow_nat \<Colon> nat \<Rightarrow> \<alpha>\<Colon>monoid \<Rightarrow> \<alpha>\<Colon>monoid"} with corresponding theorems |
418 "pow_nat :: nat \<Rightarrow> \<alpha>::monoid \<Rightarrow> \<alpha>::monoid"} with corresponding theorems |
419 |
419 |
420 @{thm pow_nat.simps [no_vars]}. |
420 @{thm pow_nat.simps [no_vars]}. |
421 |
421 |
422 \noindent As you can see from this example, for local definitions |
422 \noindent As you can see from this example, for local definitions |
423 you may use any specification tool which works together with |
423 you may use any specification tool which works together with |
540 "pow_int k x = (if k >= 0 |
540 "pow_int k x = (if k >= 0 |
541 then pow_nat (nat k) x |
541 then pow_nat (nat k) x |
542 else (pow_nat (nat (- k)) x)\<div>)" |
542 else (pow_nat (nat (- k)) x)\<div>)" |
543 |
543 |
544 text {* |
544 text {* |
545 \noindent yields the global definition of @{term [source] "pow_int \<Colon> |
545 \noindent yields the global definition of @{term [source] "pow_int :: |
546 int \<Rightarrow> \<alpha>\<Colon>group \<Rightarrow> \<alpha>\<Colon>group"} with the corresponding theorem @{thm |
546 int \<Rightarrow> \<alpha>::group \<Rightarrow> \<alpha>::group"} with the corresponding theorem @{thm |
547 pow_int_def [no_vars]}. |
547 pow_int_def [no_vars]}. |
548 *} |
548 *} |
549 |
549 |
550 subsection {* A note on syntax *} |
550 subsection {* A note on syntax *} |
551 |
551 |
557 |
557 |
558 context %quote semigroup |
558 context %quote semigroup |
559 begin |
559 begin |
560 |
560 |
561 term %quote "x \<otimes> y" -- {* example 1 *} |
561 term %quote "x \<otimes> y" -- {* example 1 *} |
562 term %quote "(x\<Colon>nat) \<otimes> y" -- {* example 2 *} |
562 term %quote "(x::nat) \<otimes> y" -- {* example 2 *} |
563 |
563 |
564 end %quote |
564 end %quote |
565 |
565 |
566 term %quote "x \<otimes> y" -- {* example 3 *} |
566 term %quote "x \<otimes> y" -- {* example 3 *} |
567 |
567 |
568 text {* |
568 text {* |
569 \noindent Here in example 1, the term refers to the local class |
569 \noindent Here in example 1, the term refers to the local class |
570 operation @{text "mult [\<alpha>]"}, whereas in example 2 the type |
570 operation @{text "mult [\<alpha>]"}, whereas in example 2 the type |
571 constraint enforces the global class operation @{text "mult [nat]"}. |
571 constraint enforces the global class operation @{text "mult [nat]"}. |
572 In the global context in example 3, the reference is to the |
572 In the global context in example 3, the reference is to the |
573 polymorphic global class operation @{text "mult [?\<alpha> \<Colon> semigroup]"}. |
573 polymorphic global class operation @{text "mult [?\<alpha> :: semigroup]"}. |
574 *} |
574 *} |
575 |
575 |
576 section {* Further issues *} |
576 section {* Further issues *} |
577 |
577 |
578 subsection {* Type classes and code generation *} |
578 subsection {* Type classes and code generation *} |