C++程式設計:代數資料型別的模式匹配

概念理解

在函數語言程式設計中,從已有的型別構造一個新型別有兩種主要的操作:

乘積

,透過這兩種操作產生的新型別稱為

代數資料型別

(Algebraic Data Type)

和型別

,型別A和型別B的和是一個包含

A例項或B例項

新型別。C++中enum、union、std::variant、std::optional、std::any型別。

積型別

,型別A和型別B的積是一個包含

A例項和B例項

新型別,即型別A集合和型別B集合中所有值的笛卡爾積。C++中使用std::pair和std::tuple產生積型別。

隨著C++中tuple和variant等工具對代數資料型別的更好支援,與它們互動的機制的重要性也有所增加。雖然已經添加了apply和visit等機制,但它們的使用非常複雜,即使在簡單的情況下也是有限的。

模式匹配

(Pattern Matching)

是許多程式語言廣泛採用的與代數資料型別互動的機制,可以極大地簡化C++。

C++模式匹配提案:

http://www。open-std。org/jtc1/sc22/wg21/docs/papers/2020/p1371r2。pdf

C++程式設計:代數資料型別的模式匹配

提案語法示例

函數語言程式設計正規化:

函數語言程式設計風格建立在簡單的、日常的數學直覺之上:若一個過程或方法沒有副作用, 那麼在忽略效率的前提下,我們需要理解的一切便只剩下如何將輸入對映到輸出了 —— 也就是說,我們只需將它視作一種計算數學函式的具體方法即可。這也是 “函數語言程式設計”中“函式式”一詞的含義之一。程式與簡單數學物件之間這種直接的聯絡, 同時支撐了對程式行為進行形式化證明的正確性以及非形式化論證的可靠性。函數語言程式設計中“函式式”一詞的另一個含義是它強調把函式作為‘一等’的值 —— 即,這類值可以作為引數傳遞給其它函式,可以作為結果返回, 也可以包含在資料結構中等等。這種將函式當做資料的方式, 產生了大量強大而有用的程式設計習語(Idiom)。其它常見的函式式語言特性包括‘代數資料型別(Algebraic Data Type)’, 能讓構造和處理豐富資料結構更加簡單的‘模式匹配(Pattern Matching)’, 以及用來支援抽象和程式碼複用的‘多型型別系統(Polymorphic Type System)’。

現有實現方式示例

#include #include #include #include // 建立可過載的表示式集合template struct overloaded : Ts。。。 { using Ts::operator()。。。; };template overloaded(Ts。。。) -> overloaded;templateusing Ptr = std::shared_ptr;// 代數資料結構struct Nil {};templatestruct Cons { T h; Ptr>> ts; Cons(T a, Ptr>> b): h(a) { ts = b; };};templateusing list = std::variant>;templatePtr> nil() { return std::make_shared>(Nil());}templatePtr> cons(T a, Ptr> b) { return std::make_shared>(Cons(a,b));}// 模式匹配templateauto match(Ptr> l, Func f, Func2 g) { return std::visit(overloaded { [&](Nil n) {return f(n); }, [&](Cons c) { return g(c。h, c。ts); } }, *l);}// 遞迴列印templatevoid print(Ptr> l) { match(l, [](Nil n) { (void)n;std::cout << “null” << std::endl; }, [](T t, Ptr> tail){ std::cout << t << “ ”; print(tail); });}int main() { auto l = cons(3, cons(4, cons(5, nil()))); print(l); return 0;}

C++程式設計:代數資料型別的模式匹配

線上編譯測試

https://wandbox。org/nojs/gcc-headhttps://wandbox。org/nojs/clang-head