Черты в Rust кажутся, по крайней мере, внешне похожими на typeclasses в Haskell, однако я видел людей напишите, что между ними есть некоторые различия. Мне было интересно, что это за различия.
В чем разница между чертами Rust и typeclasses в Haskell?
Ответ 1
На базовом уровне нет большой разницы, но они все еще есть.
Haskell описывает функции или значения, определенные в классе типов как "методы", так же, как черты описывают методы ООП в объектах, которые они включают. Тем не менее, Haskell работает с ними по-разному, рассматривая их как отдельные значения, а не прикрепляя их к объекту, как это может привести ООП. Это примерно самая очевидная разница на уровне поверхности.
Единственное, что Руст некоторое время не мог сделать, это типизированные черты высшего порядка, такие как печально известные классы типов Functor
и Monad
.
Это означает, что признаки Rust могут описывать только то, что часто называют "конкретным типом", другими словами, тип без общего аргумента. Haskell с самого начала мог создавать классы типов высшего порядка, которые используют типы, аналогичные тому, как функции высшего порядка используют другие функции: используя одну для описания другой. В течение некоторого времени это было невозможно в Rust, но поскольку связанные элементы были реализованы, такие черты стали обычным явлением и стали идиоматическими.
Поэтому, если мы игнорируем расширения, они не совсем одинаковы, но каждое из них может приблизительно соответствовать тому, что может сделать другое.
Также следует упомянуть, как сказано в комментариях, что GHC (главный компилятор Haskell) поддерживает дополнительные параметры для классов типов, включая многопараметрические (то есть многие типы задействованы) классов типов и функциональные зависимости, прекрасный вариант, который позволяет выполнять вычисления на уровне типов и приводит к семействам типов. Насколько мне известно, у Rust нет ни funDeps, ни семейства типов, хотя это может произойти в будущем. †
В целом, черты и классы типов имеют фундаментальные различия, которые из-за того, как они взаимодействуют, заставляют их действовать и в конечном итоге кажутся очень похожими.
† Хорошую статью о классах типов Haskell (включая более типизированные) можно найти здесь, а главу Rust by Example о чертах можно найти здесь
Ответ 2
Я думаю, что текущие ответы упускают из виду самые фундаментальные различия между чертами Rust и классами типа Haskell. Эти различия связаны с тем, как черты связаны с объектно-ориентированными языковыми конструкциями. Информацию об этом смотрите в книге Rust.
-
Объявление черты создает тип черты. Это означает, что вы можете объявить переменные такого типа (или, скорее, ссылки типа). Вы также можете использовать типы признаков в качестве параметров функций, структурных полей и экземпляров параметров типа.
Ссылочная переменная признака может во время выполнения содержать объекты разных типов, если тип выполнения ссылочного объекта реализует признак.
// The shape variable might contain a Square or a Circle, // we don't know until runtime let shape: &Shape = get_unknown_shape(); // Might contain different kinds of shapes at the same time let shapes: Vec<&Shape> = get_shapes();
Это не так, как работают классы типов. Классы типов не создают типов, поэтому вы не можете объявлять переменные с именем класса. Классы типов действуют как границы параметров типов, но параметры типа должны быть созданы с конкретным типом, а не с самим классом типа.
У вас не может быть списка разных вещей разных типов, которые реализуют один и тот же класс типов. (Вместо этого экзистенциальные типы используются в Haskell для выражения аналогичной вещи.) Примечание 1
-
Методы черты могут быть динамически отправлены. Это сильно связано с тем, что описано в разделе выше.
Динамическая диспетчеризация означает, что тип времени выполнения объекта, на который указывает ссылка, используется для определения того, какой метод вызывается через ссылку.
let shape: &Shape = get_unknown_shape(); // This calls a method, which might be Square.area or // Circle.area depending on the runtime type of shape print!("Area: {}", shape.area());
Снова, экзистенциальные типы используются для этого в Haskell.
В заключение
Мне кажется, что черты, по сути, те же, что и у классов типов. Кроме того, они обладают функциональностью объектно-ориентированных интерфейсов.
С другой стороны, классы типов Haskell являются более продвинутыми, поскольку Haskell имеет, например, типы с более высоким родом и расширения, такие как классы многопараметрических типов. Но я думаю, что они по сути одинаковы.
Примечание 1. В последних версиях Rust есть обновление, позволяющее дифференцировать использование имен признаков в качестве типов и использование имен признаков в качестве границ. В типе черты имя начинается с ключевого слова dyn
. Смотрите, например, этот ответ для получения дополнительной информации.
Ответ 3
"Черты" ржавчины аналогичны классам типа Haskell.
Основное отличие от Haskell заключается в том, что черты только вмешиваются для выражений с точечной нотацией, то есть формы a.foo(b).
Классы типа Haskell распространяются на типы более высокого порядка. Черты ржавчины только не поддерживают более высокие типы заказов, потому что они отсутствуют на всем языке, т.е. Это не философское различие между чертами и типами классов