Algebraic Data Types
This is one of the two chapters (alongside Chapter 8) where this course's own "origin point" framing pays off most directly and concretely. What rust1-6 introduced as Option<T> and Result<T, E> — genuinely modeled on exactly what's covered here.
data Declarations — Product Types
Point bundles two Ints together — a product type, named because the number of distinct Point values is the product of each field's own possible values. Structurally comparable to csharp2-5's own positional records, decades earlier.
Sum Types — Multiple Shapes, One Type
This is the real deal: a value of type Shape is either a Circle or a Rectangle, never a hybrid of both — a sum type, named because the total possibilities are the sum of each variant's own. This is the direct genetic ancestor of rust1-6's own data-carrying enums.
The Real Lineage — Maybe and Either ARE Just ADTs
Here's the central reveal: Maybe and Either aren't built-in language magic — they're defined using the exact same data syntax available to any programmer, sitting in the standard library like any other type. rust1-6's own Option<T> and Result<T, E> were explicitly modeled on these two — None/Some maps directly onto Nothing/Just, and Err/Ok maps directly onto Left/Right. Same shape, same idea, arriving in Haskell decades earlier.
Recursive Data Types
A data type can reference itself — a genuine binary tree needs no more than this. Recursive data alongside haskell1-4's own recursive functions, and the two ideas reinforce each other constantly: processing a Tree almost always means writing a recursive function over it.
Record Syntax for Product Types
Named-field syntax, comparable again to csharp2-5's own record syntax — Haskell's own version predates C#'s by decades too, though honestly, it carries a real historical wart C#'s doesn't share, covered next.
| Concept | Rust (rust1-6) | C# (csharp2-5) | Haskell |
|---|---|---|---|
| Product type | struct | record (positional) | data with one constructor |
| Sum type | enum with data | no direct built-in equivalent | data with | alternatives |
| "Optional value" type | Option<T> — modeled on Maybe | nullable reference types (csharp2-6) | Maybe a — the real origin |
| "Success or failure" type | Result<T, E> — modeled on Either | exceptions (csharp1-7) | Either a b — the real origin |
rust1-6's own enum design encourages applies directly here — model "this OR that, never both" as a real sum type rather than a product type with unused/optional fields simulating the same idea.
data types in the same module genuinely cannot both have a field called name without a real conflict — unlike csharp2-5's own records or Java's classes, where every field is automatically scoped to its own type with no possibility of collision. This is a well-documented, honest wart in Haskell's classic record syntax, not a made-up gotcha.
Coding Challenges
Define a sum type TrafficLight with three constructors (Red, Yellow, Green, no arguments needed), and a function next :: TrafficLight -> TrafficLight that cycles Red -> Green -> Yellow -> Red.
📄 View solutionWrite your own version of Maybe called MyMaybe (data MyMaybe a = MyNothing | MyJust a) and a function safeDivide :: Int -> Int -> MyMaybe Int that returns MyNothing on division by zero and MyJust result otherwise.
📄 View solutionDefine a recursive Tree a data type and write a function treeSum :: Tree Int -> Int that recursively sums every value in the tree, testing it on a small tree with at least 4 nodes.
📄 View solutionChapter 6 Quick Reference
- Product types (data Point = Point Int Int) bundle multiple values — comparable to csharp2-5's positional records
- Sum types (data Shape = Circle Double | Rectangle Double Double) are the real ancestor of rust1-6's own data-carrying enums
- Maybe and Either are ordinary standard-library data types, not language magic — Nothing/Just and Left/Right are the real origin of Rust's None/Some and Err/Ok
- A data type can reference itself — real recursive data (Tree a), reinforcing haskell1-4's own recursive functions
- Classic record syntax has a genuine field-naming collision limitation across types in the same module — a real wart C#'s own records don't share
- Next chapter: pattern matching — the real origin of the style rust1-6's match and csharp2-5's own pattern matching both descend from