代码之家  ›  专栏  ›  技术社区  ›  Prankster

我们需要C#中的不动点组合子吗?

  •  3
  • Prankster  · 技术社区  · 17 年前

    fixed point combinator 另一个没有。在下面的代码中,f1是使用combinator构建的,f2是直接定义的。我的问题是,我们是否需要C#中的定点组合符,或者该语言已经提供了我们所需要的一切,所以我们可以不使用它们?

    class Program
    {
        static Func<T, T> F<T>(Func<Func<T,T>,Func<T,T>> f)
        {
            return x => f(F(f))(x);
        }
    
        static void Main(string[] args)
        {
            Func<Func<int,int>,Func<int,int>> f = fac => x => x == 0 ? 1 : x * fac(x - 1);
            var f1 = F(f);
    
            Console.WriteLine(f1(5));
    
            Func<int, int> f2 = null;
            f2 = x => x == 0 ? 1 : x * f2(x - 1);
    
            Console.WriteLine(f2(5));
        }
    }
    
    4 回复  |  直到 17 年前
        1
  •  4
  •   Daniel Earwicker    17 年前

    请注意,问题中给出的第二种方法涉及在引入变量后更改变量的值,使其不是“纯”函数编程。 只有当你的函数演算系统没有一个内置的函数概念,在定义完全定义之前,可以通过名称引用它自己的定义,Y-combinator才是必要的。C#有两种方法可以直接做到这一点:1。最初将函数变量定义为null和2。声明一个普通的命名方法(到目前为止是首选技术)。

        2
  •  3
  •   user235188 user235188    16 年前

    我认为,使用一个名为Recursive的额外实用程序类,它可以相当优雅,如下所示:

    public static class Recursive {
                public static Func<R> Func<R>(
                    Func<Func<R>, Func<R>> f) { 
                    return () => f(Func(f))(); }
                public static Func<T1, R> Func<T1, R>(
                    Func<Func<T1, R>, Func<T1, R>> f) { 
                    return x => f(Func(f))(x); }
                public static Func<T1, T2, R> Func<T1, T2, R>(
                    Func<Func<T1, T2, R>, Func<T1, T2, R>> f) {
                    return (a1, a2) => f(Func(f))(a1, a2);
                }
                //And so on...
            }
    
    class Program {
    
        static void Main(string[] args) {
    
            Console.WriteLine(
                Recursive.Func<int, int>(factorial =>
                    x => x == 0 ? 1 : factorial(x - 1) * x
                ) 
                (10)
            );
    
            Console.WriteLine(
                Recursive.Func<int,int,int>(gcd =>
                    (x,y) => 
                        x == 0 ? y:
                        y == 0 ? x:
                        x > y  ? gcd(x % y, y):
                        gcd(y % x, x)
                )
                (35,21)
            );
        }
    }
    
        3
  •  1
  •   Christian C. Salvadó    17 年前

    static Func<int, int> Factorial = (n) => n <= 1 ? 1 : n*Factorial(n - 1);
    
        4
  •  -2
  •   MichaelGG    17 年前

    “需要”是什么意思?C#不需要它们,因为您不应该在C#中尝试这种函数式编程。这只是一条通往痛苦的道路。

    记忆递归函数是一个需要定点组合器的地方。比较一下这个 C# Haskell .

    因此,在C#“需要”这一点之前,需要做大量的工作才能使这类编程合理实用。