C#でもADTっぽい値の処理が簡潔に書けるようになりました。他の言語のADT定義構文と比較すると、C#ではADTっぽい型を定義するために必要な記述量が大変多いです。この記事では、ADTっぽい機能とは何か、どう役に立つかを「事前知識:代数的データ型(ADT)」セクションで紹介した後、「記述量の比較」セクションで実際に他言語の同様の機能との記述量を比較していきます。事前知識:代数的データ型(ADT)C#的には「ADTは値を持てるenumのような構造だよ」と説明するとわかりやすいかもしれません。Wikipediaによる説明を参考にしても良さそうです。以下の「実例」のセクションを読んでも直感が得られるように書いてあります。StrictSqrtを例にとって説明します。StrictSqrtはint型の値を受け取って、その値の平方根のint型の値を返す関数です。通常のSqrtとは違い、負の値が渡された場合は引数が不正である旨を、負以外の引数が渡されて、整数の平方根が存在しないときはその旨を返すこととします。このようなとき、どう書けばいいでしょうか?値に着目してint型を返す関数として書き始めると、以下のように異なる種類を表す方法がうまく書けません。//答えが存在しないという情報が返せない}種類に着目してenumで種類を返す関数として書き始めると、以下のように値がうまく書けません。EnumResult.Fail;}上の2通りの方法を良いとこ取りして、以下のように値を持ったenumのように書けたら便利そうです。Fail();}StrictSqrt関数が返すResult型の値は、こちらもやはり値を持ったenumのように以下のように使えたら便利そうです。Console.WriteLine($"{i}は不正な引数です。Console.WriteLine($"{i}の整数根は存在しません。Console.WriteLine($"{i}のルートは{n}です。Failを定義すると、上のコードは有効なC#8.0のコードになります。実行結果は以下のようになります。結果-5は不正な引数です。(負の数)-4は不正な引数です。(負の数)-3は不正な引数です。(負の数)-2は不正な引数です。(負の数)-1は不正な引数です。(負の数)0のルートは0です。2の整数根は存在しません。3の整数根は存在しません。5の整数根は存在しません。6の整数根は存在しません。7の整数根は存在しません。8の整数根は存在しません。C#で使える値を持ったenumっぽいもの、すなわちADTっぽいものの雰囲気と、その使いみちがわかっていただけたでしょうか?記述量の比較C#ではADTっぽい値を使う側は簡潔に使えるが、型の定義が記述量が多いと先程述べました。C#で作り、記述量を比較します。本来は型の定義、値の作成、値の使用の順番で紹介するのが自然な流れかもしれません。この記事の目的は、これら3つのうち型の定義が他の2つと比べて記述量が多いことを実感してもらうことにあります。そのため、値の作成、値の使用の記述を先に比較して、最後に型の定義の記述に触れようと思います。今回ADTで表す数式は以下のBNFで表されるものです。数式のいずれかの形をしていることを意味しています。以下では、この数式を表すADTの型をExpr型(あるいはexpr型)としています。今回の例中に直接は出てきませんが、main関数は数式myExprと、それを計算した値の両方を表示する操作を行うとします。myExprを定義することとします。Scalaと比べてそれほど変わらない記述量(&それほど変わらない記法)で、C#でも記述できます。Haskellでは以下のように書けます。(定数整数)の意味です。OCamlでは以下のように書けます。5)))Scalaでは以下のように書けます。CInt(5)))C#では以下のように書けます。CInt(5)));確かにそれほど変わらない記述量ですね。数式の計算を行うcalc関数を比較します。Scalaとそれほど変わらない記述量(&記法)でC#でも値が使用できます。Haskellでは以下のように書けます。rOCamlでは以下のように書けます。rScalaでは以下のように書けます。calc(r)}C#では以下のように書けます。Calc(r)};こちらも確かにそれほど変わらない記述量で書けています。Scalaと比べるとC#では必要な記述量がかなり多くなってしまいます。Haskellでは以下のように書けます。ShowOCamlでは以下のように書けます。show]Scalaでは以下のように書けます。ExprC#では以下のようにかなり記述量が多くなってしまいます。{Right})";}つ、つらい、、、まとめC#はADTっぽい値を気軽に使えるように進化してきました。それでもまだ、ADTっぽい型を定義するのはかなり苦労します。型を定義する側も少ない記述量でできるようになるといいなあ。今回のコードたちのgistです。recordsという機能のpropsalはだいぶ近い話かもしれません?++C++というサイトにこのあたりの話が非常にわかりやすくまとまっています。switchの拡張(型スイッチ)などのページをおすすめします。Show周りの条件を揃えたかったためです。Showに相当するtoStringが実装されています。使う機能なので、本質ではないにせよ、この機能を持つ側で揃えて比較しようと思いました。upLoginユーザーは見つかりませんでした。