Подумайте, какой должна быть подпись для методов IMonad<T>
. В Haskell класс типов Monad определяется как
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
Сложно перевести это непосредственно на интерфейс C #, потому что вы должны иметь возможность ссылаться на конкретный подтип реализации ("m a" или ISpecificMonad<a>
) в определении общего интерфейса IMonad. Хорошо, вместо того, чтобы пытаться (например) IEnumerable<T>
реализовать IMonad<T>
напрямую, мы попытаемся выделить реализацию IMonad в отдельный объект, который может быть передан вместе с конкретным экземпляром типа монады тому, что нужно рассматривайте это как монаду (это «стиль передачи словаря»). Это будет IMonad<TMonad>
, а TMonad здесь будет не буквой T в IEnumerable<T>
, а самой IEnumerable<T>
. Но подождите - это тоже не может работать, потому что, например, подпись Return<T>
должна привести нас от любого типа T к TMonad<T>
, для любого TMonad<>
. IMonad должен быть определен как что-то вроде
interface IMonad<TMonad<>> {
TMonad<T> Unit<T>(T x);
TMonad<U> SelectMany<T, U>(TMonad<T> x, Func<T, TMonad<U>> f);
}
с использованием гипотетической функции C #, которая позволила бы нам использовать конструкторы типов (например, TMonad <>) в качестве параметров универсального типа. Но, конечно, C # не имеет этой функции (полиморфизм с более высоким родом) . Вы можете модифицировать конструкторы типов во время выполнения (typeof(IEnumerable<>)
), но не можете ссылаться на них в сигнатурах типов без указания параметров. Таким образом, помимо -100 баллов, реализация этого «правильно» потребует не просто добавления другого обычного определения интерфейса, но и глубоких дополнений к системе типов.
Именно поэтому возможность иметь понимание запросов по вашим собственным типам взломана (они просто «магически» работают, если есть правильные имена магических методов с правильными сигнатурами) вместо использования механизма интерфейса и т. Д.