Вот одно отличие, о котором следует помнить:
C # имеет подтипы, но у Haskell нет, что означает, с одной стороны, что вы знаете больше вещей, просто взглянув на тип Haskell.
id :: a -> a
Эта функция Haskell принимает значение типа и возвращает то же значение того же типа.
Если вы дадите ему Bool
, он вернет Bool
. Дайте ему Int
, он вернет Int
. Дайте ему Person
, он вернет Person
.
В C # вы не можете быть так уверены. Это та «функция» в C #:
public T Id<T>(T x);
Теперь из-за подтипа вы можете назвать это так:
var pers = Id<Person>(new Student());
Хотя pers
имеет тип Person
, аргумент функции Id
- нет. На самом деле pers
может иметь более конкретный тип, чем просто Person
. Person
может даже быть абстрактным типом, гарантируя, что pers
будет иметь более конкретный тип.
Как видите, даже с такой простой функцией, как id
, система типов .NET уже позволяет гораздо больше, чем система более строгих типов из Haskell
. Хотя это может быть полезно для некоторой работы по программированию, это также усложняет рассуждение о программе, просто просматривая типы вещей (что очень приятно делать в Haskell).
И, во-вторых, в Haskell есть ad hoc полиморфизм (он же перегрузка) через механизм, известный как «классы типов».
equals :: Eq a => a -> a -> Bool
Эта функция проверяет, равны ли два значения. Но не только любые два значения, а только значения, которые имеют экземпляры для класса Eq
. Это своего рода ограничения на параметры типа в C #:
public bool Equals<T>(T x, T y) where T : IComparable
Однако есть разница. С одной стороны, подтип: вы можете создать его с помощью Person
и вызвать его с помощью Student
и Teacher
.
Но есть и разница в том, к чему это компилируется. Код C # компилируется почти точно так, как говорит его тип. Проверка типов гарантирует, что аргументы реализуют правильный интерфейс, и чем вы хороши.
Принимая во внимание, что код на Haskell соответствует примерно так:
equals :: EqDict -> a -> a -> Bool
Функция получает дополнительный аргумент , словарь всех функций, необходимых для выполнения Eq
вещей. Вот как вы можете использовать эту функцию и для чего она компилируется:
b1 = equals 2 4 --> b1 = equals intEqFunctions 2 4
b2 = equals True False --> b2 = equals boolEqFunctions True False
Это также показывает, что делает подтип такой болью, представьте, если это возможно.
b3 = equals someStudent someTeacher
--> b3 = equals personEqFunctions someStudent someTeacher
Как определить словарь personEqFunctions
, если Student
равно Teacher
? У них даже нет одинаковых полей.
Короче говоря, хотя ограничения типа Haskell на первый взгляд могут выглядеть как ограничения типа .NET, они реализованы совершенно по-разному и компилируются в две действительно разные вещи.