Здравствуйте, Sinclair, Вы писали:
S>0. 90% из того, о чём он рассуждает — это сложный способ разрешить определять operator+ за пределами типа.
S>В плюсах этой проблемы нет как класса благодаря наличию свободных функций; в шарпе этого нет — в итоге имеем печальный итог: мы не можем описать оператор+ для аргументов типа A и B, не будучи авторами A или B.
Проблема определить
оператор сложения вне типа никак и ничем принципиально не отличается от проблемы определить
оператор сравнения вне типа. Это ровно та же проблема для ровно тех же задач — написание обобщённых алгоритмов и структур данных, которые используют полиморфные сложения и сравнения.
Алгоритмы, использующие обобщённое сравнение всем известны: сортировки, деревья, хэш-таблицы. Использование компаратора ни у кого удивления не вызывает.
Алгоритмы, использующие обобщённое сложение никому кроме меня не известны: например, алгоритм Дейкстры на графах. Поэтому использование моноида вызывает бурю эмоций.
Для обобщённого сравнения ты реализуешь IComparer<T> или IEqualityComparer<T>. Аналогично, для обобщённого сложения (обобщённой бинарной операции) ты реализуешь IMonoid<T>. Или, если ты больше не инженер, а уже менеджер, то IGenericAggregationControllerManager<T>, так трудовому народу понятнее.
S>1. Рассказ про то, что у инта сразу два моноида, был убедителен, но непонятно, как именно это можно применить. Ну, кроме вырожденного случая "давайте проагрегируем массив интов с использованием 1 и * в качестве нашего моноида".
Давай не про инты, а про float'ы, ок? Аддитивный моноид понятно, например, складывать веса дуг вдоль пути на графе. Мультипликативный моноид, например, когда у тебя цепочка процентных ставок: начинаем с 1.0, заплатили налог 13% (домножить на 0.87), получили interest 5% (домножить на 1.05) и так далее.
Точно так же, как у тебя могут быть разные компараторы для одного типа (сравнение строк с учётом регистра, без учёта культуры, etc.), так и моноиды могут быть разные для одного типа.
Взя затея вокруг шейпов — это добавить чуть синтаксического сахара вокруг всех этих IEqualityComparer<T>'ов и IMonoid<T>'ов, чтоб передавать не инстансы (они ж все одинаковые stateless), а сами типы. Примерно, как в этой старой статье:
https://github.com/MattWindsor91/roslyn/blob/master/concepts/docs/csconcepts.md