| # Enumerated Types | |
| The simplest kind of inductive type is simply a type with a finite, enumerated list of elements. | |
| The following command declares the enumerated type `Weekday`. | |
| ```lean | |
| inductive Weekday where | |
| | sunday : Weekday | |
| | monday : Weekday | |
| | tuesday : Weekday | |
| | wednesday : Weekday | |
| | thursday : Weekday | |
| | friday : Weekday | |
| | saturday : Weekday | |
| ``` | |
| The `Weekday` type has 7 constructors/elements. The constructors live in the `Weekday` namespace | |
| Think of `sunday`, `monday`, …, `saturday` as being distinct elements of `Weekday`, | |
| with no other distinguishing properties. | |
| ```lean | |
| # inductive Weekday where | |
| # | sunday : Weekday | |
| # | monday : Weekday | |
| # | tuesday : Weekday | |
| # | wednesday : Weekday | |
| # | thursday : Weekday | |
| # | friday : Weekday | |
| # | saturday : Weekday | |
| #check Weekday.sunday -- Weekday | |
| #check Weekday.monday -- Weekday | |
| ``` | |
| You can define functions by pattern matching. | |
| The following function converts a `Weekday` into a natural number. | |
| ```lean | |
| # inductive Weekday where | |
| # | sunday : Weekday | |
| # | monday : Weekday | |
| # | tuesday : Weekday | |
| # | wednesday : Weekday | |
| # | thursday : Weekday | |
| # | friday : Weekday | |
| # | saturday : Weekday | |
| def natOfWeekday (d : Weekday) : Nat := | |
| match d with | |
| | Weekday.sunday => 1 | |
| | Weekday.monday => 2 | |
| | Weekday.tuesday => 3 | |
| | Weekday.wednesday => 4 | |
| | Weekday.thursday => 5 | |
| | Weekday.friday => 6 | |
| | Weekday.saturday => 7 | |
| #eval natOfWeekday Weekday.tuesday -- 3 | |
| ``` | |
| It is often useful to group definitions related to a type in a namespace with the same name. | |
| For example, we can put the function above into the ``Weekday`` namespace. | |
| We are then allowed to use the shorter name when we open the namespace. | |
| In the following example, we define functions from ``Weekday`` to ``Weekday`` in the namespace `Weekday`. | |
| ```lean | |
| # inductive Weekday where | |
| # | sunday : Weekday | |
| # | monday : Weekday | |
| # | tuesday : Weekday | |
| # | wednesday : Weekday | |
| # | thursday : Weekday | |
| # | friday : Weekday | |
| # | saturday : Weekday | |
| namespace Weekday | |
| def next (d : Weekday) : Weekday := | |
| match d with | |
| | sunday => monday | |
| | monday => tuesday | |
| | tuesday => wednesday | |
| | wednesday => thursday | |
| | thursday => friday | |
| | friday => saturday | |
| | saturday => sunday | |
| end Weekday | |
| ``` | |
| It is so common to start a definition with a `match` in Lean, that Lean provides a syntax sugar for it. | |
| ```lean | |
| # inductive Weekday where | |
| # | sunday : Weekday | |
| # | monday : Weekday | |
| # | tuesday : Weekday | |
| # | wednesday : Weekday | |
| # | thursday : Weekday | |
| # | friday : Weekday | |
| # | saturday : Weekday | |
| # namespace Weekday | |
| def previous : Weekday -> Weekday | |
| | sunday => saturday | |
| | monday => sunday | |
| | tuesday => monday | |
| | wednesday => tuesday | |
| | thursday => wednesday | |
| | friday => thursday | |
| | saturday => friday | |
| # end Weekday | |
| ``` | |
| We can use the command `#eval` to test our definitions. | |
| ```lean | |
| # inductive Weekday where | |
| # | sunday : Weekday | |
| # | monday : Weekday | |
| # | tuesday : Weekday | |
| # | wednesday : Weekday | |
| # | thursday : Weekday | |
| # | friday : Weekday | |
| # | saturday : Weekday | |
| # namespace Weekday | |
| # def next (d : Weekday) : Weekday := | |
| # match d with | |
| # | sunday => monday | |
| # | monday => tuesday | |
| # | tuesday => wednesday | |
| # | wednesday => thursday | |
| # | thursday => friday | |
| # | friday => saturday | |
| # | saturday => sunday | |
| # def previous : Weekday -> Weekday | |
| # | sunday => saturday | |
| # | monday => sunday | |
| # | tuesday => monday | |
| # | wednesday => tuesday | |
| # | thursday => wednesday | |
| # | friday => thursday | |
| # | saturday => friday | |
| def toString : Weekday -> String | |
| | sunday => "Sunday" | |
| | monday => "Monday" | |
| | tuesday => "Tuesday" | |
| | wednesday => "Wednesday" | |
| | thursday => "Thursday" | |
| | friday => "Friday" | |
| | saturday => "Saturday" | |
| #eval toString (next sunday) -- "Monday" | |
| #eval toString (next tuesday) -- "Wednesday" | |
| #eval toString (previous wednesday) -- "Tuesday" | |
| #eval toString (next (previous sunday)) -- "Sunday" | |
| #eval toString (next (previous monday)) -- "Monday" | |
| -- .. | |
| # end Weekday | |
| ``` | |
| We can now prove the general theorem that ``next (previous d) = d`` for any weekday ``d``. | |
| The idea is to perform a proof by cases using `match`, and rely on the fact for each constructor both | |
| sides of the equality reduce to the same term. | |
| ```lean | |
| # inductive Weekday where | |
| # | sunday : Weekday | |
| # | monday : Weekday | |
| # | tuesday : Weekday | |
| # | wednesday : Weekday | |
| # | thursday : Weekday | |
| # | friday : Weekday | |
| # | saturday : Weekday | |
| # namespace Weekday | |
| # def next (d : Weekday) : Weekday := | |
| # match d with | |
| # | sunday => monday | |
| # | monday => tuesday | |
| # | tuesday => wednesday | |
| # | wednesday => thursday | |
| # | thursday => friday | |
| # | friday => saturday | |
| # | saturday => sunday | |
| # def previous : Weekday -> Weekday | |
| # | sunday => saturday | |
| # | monday => sunday | |
| # | tuesday => monday | |
| # | wednesday => tuesday | |
| # | thursday => wednesday | |
| # | friday => thursday | |
| # | saturday => friday | |
| theorem nextOfPrevious (d : Weekday) : next (previous d) = d := | |
| match d with | |
| | sunday => rfl | |
| | monday => rfl | |
| | tuesday => rfl | |
| | wednesday => rfl | |
| | thursday => rfl | |
| | friday => rfl | |
| | saturday => rfl | |
| # end Weekday | |
| ``` |