簡體   English   中英

如何在C#中編寫咖喱方法?

[英]How to write a curried method in C#?

以下代碼將運行並打印11

using System;
class MainClass {
  public static void Main (string[] args) {
    Func<int, int, int> _Add = (x,y) => x + y;
    var Add = Curry(_Add);
    int z = Add (5) (6);
    Console.WriteLine(z); // 11
  }

  public static Func<T1, Func<T2, T3>> Curry<T1, T2, T3>(Func<T1, T2, T3> f) {
    return x => y => f(x, y);
  }
}

但是我想知道是否有可能在類上而不是本地定義curried方法

public static ... Add(...) { /* define curried form using Curry helper */
  return f(x, y); 
}

這樣應該可以調用

public static void Main(string[] args) {
  Add (5) (6); // => should return 11
}

如果我想使用很多方法,最好使用一個輔助函數來定義它們。 手工寫每個都太累了。 無論如何,我無法為此找到合適的語法。 請幫忙。 我是C#菜鳥。

您可以從Add返回一個Func<int, int>

public static Func<int, int> Add(int x) { 
    return y => x + y;
}

或將其聲明為屬性:

public static Func<int, Func<int, int>> Add
{
    get { return x => y => x + y; }
}

使用原始的咖喱,構造函數可以初始化函數。 您需要哪種類型的靈活性?

public static class Test
{
    static Test()
    {
        Add = Curry<int,int,int>((x, y) => x+y);
        Multiply = Curry<int,int,int>((x, y) => x*y);
    }

    public static Func<int, Func<int, int>> Add { get; }
    public static Func<int, Func<int, int>> Multiply { get; }

    public static Func<T1, Func<T2, T3>> Curry<T1, T2, T3>(Func<T1, T2, T3> f) {
      return x => y => f(x, y);
    }
}

對於一堆方法實現,它們可以像這樣包含

public static class Test
{
    public static Func<int, Func<int, int>> Add => x => y => x + y;
    public static Func<int, Func<int, int>> Multiply => x => y => x * y;
}

要咖喱函數,您首先需要將一個函數傳遞給一個函數。

void Main()
{
    var test = Add(() => 5)(6);
    test.Dump();
}

public Func<int, int> Add(Func<int> a)
{
    return (x) => x + a();
}

//returns 11

理想情況下,您希望使用currying和部分應用程序,當您有許多參數時,currying變得效率很低。 當我這樣做時,我實現了很多稱為currypar的靜態方法,這些方法最多可以處理10個參數並部分應用N個值。

這是4個參數的示例:

public static Func<T1, Func<T2, Func<T3, Func<T4, R>>>> curry<T1, T2, T3, T4, R>(Func<T1, T2, T3, T4, R> f) =>
        (T1 a) => (T2 b) => (T3 c) => (T4 d) => f(a, b, c, d);

它很快以許多嵌套的委托結束。 這是部分應用程序出現的地方:

public static Func<T4, R> par<T1, T2, T3, T4, R>(Func<T1, T2, T3, T4, R> func, T1 a, T2 b, T3 c) =>
        (T4 d) => func(a, b, c, d);

要使用上面的curyring示例,您可以執行以下操作:

var f = curry(func);
var r = f(1)(2)(3)(4);

但是經常需要部分應用程序:

var f = par(1,2,3);
var r = f(4);

這已在我的C#功能庫中完全實現: language-ext

咖喱來源

部分應用程序源

您可以按原樣處理這些源文件,沒有任何外部依賴關系。

在您的示例中,您可以這樣聲明一個Add方法:

class Test
{
    public static readonly Func<int, Func<int, int>> Add => x => y => x + y;
}

或使用經典的curry功能:

class Test
{
    public static readonly int Add(int x, int y) => x + y;
}

var add = curry(Test.Add);
var r = add(1)(2);

或部分申請:

class Test
{
    public static int Add(int x, int y) => x + y;
}

var addOne = par(Test.Add, 1);
var r = addOne(2);

暫無
暫無

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

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