2013-08-17 5 views
4

Я возился вокруг в Visual Studio, и я обнаружил, чтоСуществует ли использование типа делегата, который возвращает делегат того же типа, что и сам?

delegate RecursiveDelegate RecursiveDelegate(); 

является допустимым определение делегата.

У меня нет большого опыта функционального программирования, но мне было интересно, действительно ли этот шаблон действительно полезен в функциональном программировании или если это просто любопытство семантики. Я хочу задать этот вопрос двумя способами:

  1. В контексте с побочными эффектами. Я вижу, что на самом деле это на полпути достойный способ моделирования итерационных алгоритмов обучения на функциональном языке, где фактическая задача алгоритма выполняется как побочный эффект, а новая версия функции - это возвращаемое значение. Это сделано?
  2. В контексте без побочных эффектов. Я думаю, что это в принципе бесполезно, но мне очень любопытно, если я ошибаюсь. Может ли это быть полезным, если предположить, что реализация RecursiveDelegate() не имеет побочных эффектов?
+0

В CLR делегат представляет собой объект, который имеет метод 'Invoke' (с некоторыми дополнительными метаданными, но это его ядро). Если вы так думаете об этом, нет ничего странного в том, что он работает. Это ничего более странного, чем объект, который возвращается в метод. – zneak

+2

@zneak - Я не думаю, что вопрос в том, почему он работает (несколько разумный, поскольку функция может возвращать любой тип, который он хочет), а скорее, как/если он может быть полезен для функционального стиля программирования. –

+1

Конечно. Вот почему я не отправляю ответ. Я обращался к первому удивлению. – zneak

ответ

1

У меня есть пример некоторого аналогичного кода, который не является точным рекурсивным делегатом, но он приближается. «Я-Комбинатор» близок - и, честно говоря, я понятия не имею, как это работает на практике, но оно используется для определения рекурсивных функций.

Вот обалденный код, который нужно определить:

public delegate T S<T>(S<T> s); 

public static T U<T>(S<T> s) 
{ 
    return s(s); 
} 

public static Func<A, Z> Y<A, Z>(Func<Func<A, Z>, Func<A, Z>> f) 
{ 
    return U<Func<A, Z>>(r => a => f(U(r))(a)); 
} 

Теперь вы можете определить рекурсивные функции в одной строке.

Факториал:

var fact = Y<int, int>(_ => x => x == 0 ? 1 : x * _(x - 1)); 
var fact5 = fact(5); // == 120 
var fact6 = fact(6); // == 720 
var fact7 = fact(7); // == 5040 

Фибоначчи:

var fibo = Y<int, int>(_ => x => x <= 1 ? 1 : _(x - 1) + _(x - 2)); 
var fibo5 = fibo(5); // == 8 
var fibo6 = fibo(6); // == 13 
var fibo7 = fibo(7); // == 21 

Моя любимая линия в коде вызова s(s). Серьезно, если кто-то может выправить это из головы, они гений! Не говоря уже о целом U<Func<A, Z>>(r => a => f(U(r))(a)).

Смежные вопросы