Определение родовых типов с функциональной композицией - PullRequest
6 голосов
/ 22 мая 2011

Предположим, я хочу реализовать функциональную композицию, например:

    public Func<T,T> Compose<T>(Func<T,T> f, Func<T,T> g)
    {
        return new Func<T,T>( x => f(g(x)));
    }

Теперь на практике я могу использовать этот Compose () fn так:

    public String ToUpper(String s) { return s.ToUpper(); }        
    public String Replicate(String s) { return s+s; }

    public void Run()
    {
        var h = Compose<String>(ToUpper, Replicate);
        System.Console.WriteLine("{0}", h("fred"));
    }

И результат FREDFRED.

Есть ли способ использовать более простой синтаксис для вызова Compose? Я пытался так:

        var h = Compose(ToUpper, Replicate);

... но я получаю ошибку компиляции:

ошибка CS0411: аргументы типа для метода «FunctionalTest.Compose (System.Func, System.Func)» не могут быть выведены из использования. Попробуйте указать аргументы типа явно.

Вполне понятно. Я задаюсь вопросом, возможно ли объявить это по-другому и получить заключение, чтобы фактически работать.


EDIT
Происхождение проблемы: я смотрел онлайн-лекцию старшекурсника по функциональному программированию, CS61A Калифорнийского университета в Беркли. (найти его на YouTube). У меня нет никакого официального обучения по FP, и я подумал, что могу чему-то научиться. Проф использует схему, и он говорит о том, что схема + lisp являются чисто функциональными языками, а другие языки менее. Он определенно определил, что Pascal, C, C ++ и Java (но не C #) лишены функциональных возможностей, и сказал, что будет сложно создать функциональную композицию с этими языками («Не стоять на голове»). Он утверждал, что указатель на функцию (как доступно в C, C ++) - это не то же самое, что функция «сущность», лямбда. Я понимаю.

Забавно - он не упомянул Javascript или C #, которые я считаю основными языками, и оба имеют довольно хорошие функциональные возможности. (Я не знаю F #.)

Мне любопытно, что это лекция прошлого года - 14 месяцев назад - и все же он, похоже, не знает о функциональных аспектах основных, современных языков.

Так что я следую и выполняю упражнения, но вместо схемы или шрифта я использую C #. А также делать некоторые из них в Javascript.

В любом случае, спасибо всем за качественные ответы.

Ответы [ 4 ]

4 голосов
/ 23 мая 2011

Добавление к ответу lasseespeholt, если вы определили Compose как метод расширения (переименованный в «Тогда», чтобы результат имел больше смысла):

public static Func<T, T> Then<T>(this Func<T, T> f, Func<T, T> g)
{
    return x => g(f(x));
}

вы можете сделать это свободно:

var h = toUpper.Then(replicate); // .Then(trim) etc...
4 голосов
/ 23 мая 2011

Будет работать следующий код:

Func<string, string> toUpper = ToUpper;
Func<string, string> replicate = Replicate;

// now the compiler knows that the parameters are Func<string, string>
var h = Compose(toUpper, replicate);

Так что, возможно, вы все еще можете добиться улучшения читабельности, которое вы ищете, определяя эти переменные только один раз, и они повторно используют их на протяжении ваших тестов (я предполагаю, что это утилита для тестирования ...)

4 голосов
/ 23 мая 2011

Мне нравится ответ Ран (+1), но я думаю, что это делает его немного более лаконичным и приятным. (Работает в предположении, что у вас есть возможность переопределить функции следующим образом.)

Func<string, string> toUpper = s => s.ToUpper();
Func<string, string> replicate = s => s + s;

var h = Compose(toUpper, replicate);
2 голосов
/ 22 мая 2011

Вы также можете передать Compose параметр и получить его на самом деле оценить функцию; в этом случае он должен иметь возможность выводить тип параметра. (Возможно, вам все равно придется указать тип возвращаемого значения.)

Кроме этого, нет, в C # нет способа сделать такие вещи.

...