Что еще?
Вещь, которая идёт рука об руку с паттерн-мэтчингом -- алгебраические типы данных. Или же tagged union. В С++ есть обычный union, который для других целей. Но это очень полезная вещь в языке. Она очень хорошо помогает структурировать программу, потому что ты буквально средствами языка делаешь декомпозицию -- разбиваешь на на случаи и обрабатываешь каждый случай параллельно.
Что-нибудь базовое: data Either a b = Left a | Right b
После программирования на Haskell очень трудно привыкать к менее удобным вариантам, когда функция может вернуть либо одно либо другое.
Что-то менее тривиального из недавного: Size тип данных в библиотеке сериализации store
data Size a = ConstSize Int | VarSize (a -> Int)
Размер объекта может быть либо константным (для оптимизаций полезно) либо переменным. Дополнительным бонусом идёт то, что компилятор проверяет все паттерны на exhaustiveness. То есть на этапе компиляции можно быть уверенным, что реально все случаи обработаны. Это очень удобно, когда код рефакторится и добавляются новые случаи (правда, к сожалению, код можно написать так, что пользы от этой фичи именно в таком случае с рефакторингом не будет :( )