簡體   English   中英

C#中的依賴類型:使輸出類型取決於輸入值

[英]Dependent Types in C#: making the output type depend on the input value

我希望能夠在C#中創建一個方法,其輸出類型取決於它的參數值; 松散,

delegate B(a) DFunc<A,B>(A a);

作為一個例子,我想編寫一個函數,它接受一個整數並根據參數返回許多可能類型中的一個:

f(1) = int
f(2) = bool
f(3) = string
f(n), where n >= 4 = type of n-by-n matrices

任何幫助都會有用。

最接近的C#可以獲得您在更好的語言中習慣的酷炫功能,例如Agda是參數多態(泛型)。 幾乎沒有類型推斷 - 絕對沒有類似高級類型,類型類或隱式術語, 更高級別/不可預測類型,存在量化 *,類型族,GADT,任何類型的依賴類型,或您關心的任何其他術語提到,我不指望會有。

一方面,它沒有胃口。 C#是專為工業而非研究而設計的,絕大多數C#開發人員 - 其中許多人在00年代逃離了C ++ - 從未聽說過我上面列出的大部分概念。 設計師沒有計划添加它們:正如Eric Lippert喜歡指出的那樣,當你擁有數百萬用戶時, 語言功能並不是免費的。

另一方面,它很復雜。 C#集中具有子類型多態性,這是一個簡單的想法,與您可能需要的許多其他類型系統功能進行了令人驚訝的深度交互。 根據我的經驗,少數C#開發人員可以理解的差異只是其中的一個例子。 (事實上,分型和方差仿制葯的一般情況下, 已知的不可判定 。)更多,想想高kinded類型(是Monad m變體m ?),或類型的家庭應該如何表現時,他們的參數可以子類型。 大多數高級類型系統都不會出現子類型並非巧合:帳戶中的貨幣數量有限,而且子類型占很大比例。

也就是說,看到你可以推動它有多遠,這很有趣。 我有一個名為Fun With Generics的演講( 這里 幻燈片視頻現在可用! ),旨在向C#用戶毫無戒心的觀眾提供從屬類型的概念。 在詳細抱怨類型檢查器拒絕的正確程序,並使用上限類型做傻事后,我展示了如何濫用泛型來模擬依賴類型的最簡單的例子。 這是談話的荒謬結論:

// type-level natural numbers
class Z {}
class S<N> {}

// Vec defined as in Agda; cases turn into subclasses
abstract class Vec<N, T> {}
class Nil<T> : Vec<Z, T> {}
// simulate type indices by varying
// the parameter of the base type
class Cons<N, T> : Vec<S<N>, T>
{
    public T Head { get; private set; }
    public Vec<N, T> Tail { get; private set; }

    public Cons(T head, Vec<N, T> tail)
    {
        this.Head = head;
        this.Tail = tail;
    }
}

// put First in an extension method
// which only works on vectors longer than 1
static class VecMethods
{
    public static T First<N, T>(this Vec<S<N>, T> vec)
    {
        return ((Cons<N, T>)vec).Head;
    }
}

public class Program
{
    public static void Main()
    {
        var vec1 = new Cons<Z, int>(4, new Nil<int>());
        Console.WriteLine(vec1.First());  // 4
        var vec0 = new Nil<int>();
        Console.WriteLine(vec0.First());  // type error!
    }
}

不幸的是,如果沒有在First運行時強制轉換,就無法完成。 vecVec<S<N>, T>的事實不足以向類型檢查器證明它是Cons<N, T> (你無法證明它,因為它不是真的;有人可以在不同的程序集中Vec 。)更一般地說,沒有辦法折疊任意Vec因為編譯器不能對自然數進行歸納。 這很令人痛苦,因為即使頁面上有信息,類型檢查器也太笨了,無法讓我們收獲它。

正如Haskell人發現的那樣,將依賴類型改造為現有語言很難 當語言是一種基於子類型的命令式面向對象語言(通常難以證明定理)時更難(復雜地與參數多態性結合)。 當沒有人真正要求它時更難。

*自從寫完這個答案以來,我已經對這個主題做了更多的思考,並意識到更高級別的類型確實存在並且在C#中是正確的 這使您可以使用更高級別的存在量化編碼

您需要依賴類型才能執行此操作。 此功能僅存在於一些非主流語言中,例如Idris和Coq。

鑒於你已經正確標記了這一點,我假設你知道c#沒有那個功能那么具體是什么/為什么要問?

這不是一個真正的答案 - 正如我在評論中提到的,我不認為你所要求的是可能的。 但這證明了我認為用戶@Douglas Zare的建議。

  public void RunTest()
  {
     for (int n = 1; n <= 4; n++)
     {
        object o = F(n);

        if (o is int)
           Console.WriteLine("Type = integer, value = " + (int)o);
        else if (o is bool)
           Console.WriteLine("Type = bool, value = " + (bool)o);
        else if (o is string)
           Console.WriteLine("Type = string, value = " + (string)o);
        else if (o is float[,])
        {
           Console.WriteLine("Type = matrix");
           float[,] matrix = (float[,])o;
           // Do something with matrix?
        }
     }

     Console.ReadLine();
  }


  private object F(int n)
  {
     if (n == 1)
        return 42;

     if (n == 2)
        return true;

     if (n == 3)
        return "forty two";

     if (n >= 4)
     {
        float[,] matrix = new float[n, n];
        for (int i = 0; i < n; i++)
           for (int j = 0; j < n; j++)
              matrix[i, j] = 42f;

        return matrix;
     }

     return null;
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM