Учебники

Haskell — Типы и Тип Класс

Haskell — это функциональный язык, и он строго типизирован, что означает, что тип данных, используемый во всем приложении, будет известен компилятору во время компиляции.

Класс встроенного типа

В Haskell каждое утверждение рассматривается как математическое выражение, а категория этого выражения называется типом . Вы можете сказать, что «Тип» — это тип данных выражения, используемого во время компиляции.

Чтобы узнать больше о типе , мы будем использовать команду «: t». В общем случае Type можно рассматривать как значение, тогда как Type Class можно рассматривать как набор похожих типов. В этой главе мы узнаем о различных встроенных типах.

Int

Int является классом типа, представляющим данные типа Integer. Каждое целое число в диапазоне от 2147483647 до -2147483647 относится к классу типа Int . В следующем примере функция fType () будет вести себя в соответствии с определенным типом.

Live Demo

fType :: Int -> Int -> Int 
fType x y = x*x + y*y
main = print (fType 2 4) 

Здесь мы установили тип функции fType () как int . Функция принимает два значения типа int и возвращает одно значение типа int . Если вы скомпилируете и выполните этот фрагмент кода, он выдаст следующий вывод:

sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts 
sh-4.3$ main
20

целое число

Целое число можно рассматривать как надмножество Int . Это значение не ограничено никаким числом, поэтому целое число может иметь любую длину без каких-либо ограничений. Чтобы увидеть основное различие между типами Int и Integer , давайте изменим приведенный выше код следующим образом:

Live Demo

fType :: Int -> Int -> Int 
fType x y = x*x + y*y 
main = print (fType 212124454 44545454454554545445454544545)

Если вы скомпилируете указанный выше фрагмент кода, появится следующее сообщение об ошибке:

main.hs:3:31: Warning:            
   Literal 44545454454554545445454544545 is out of the Int range -
   9223372036854775808..9223372036854775807 
Linking main ...

Эта ошибка произошла из-за того, что наша функция fType () ожидала одно значение типа Int, и мы передали какое-то очень большое значение типа Int. Чтобы избежать этой ошибки, давайте изменим тип «Int» на «Integer» и наблюдаем разницу.

Live Demo

fType :: Integer -> Integer -> Integer 
fType x y = x*x + y*y 
main = print (fType 212124454 4454545445455454545445445454544545) 

Теперь он выдаст следующий результат:

sh-4.3$ main
1984297512562793395882644631364297686099210302577374055141

терка

Посмотрите на следующий фрагмент кода. Он показывает, как работает тип Float в Haskell —

Live Demo

fType :: Float -> Float -> Float 
fType x y = x*x + y*y 
main = print (fType 2.5 3.8)

Функция принимает два значения с плавающей запятой в качестве входных данных и возвращает другое значение с плавающей запятой в качестве выходных данных. Когда вы скомпилируете и выполните этот код, он выдаст следующий вывод:

sh-4.3$ main
20.689999 

двойной

Double — число с плавающей запятой с двойной точностью в конце. Взгляните на следующий пример —

Live Demo

fType :: Double -> Double -> Double 
fType x y = x*x + y*y 
main = print (fType 2.56 3.81)

Когда вы выполните приведенный выше фрагмент кода, он сгенерирует следующий вывод:

sh-4.3$ main 
21.0697

Bool

Bool — это логический тип. Это может быть как True, так и False. Выполните следующий код, чтобы понять, как работает тип Bool в Haskell:

Live Demo

main = do  
   let x = True 
   
   if x == False 
      then putStrLn "X matches with Bool Type" 
   else putStrLn "X is not a Bool Type" 

Здесь мы определяем переменную «x» как Bool и сравниваем ее с другим логическим значением, чтобы проверить ее оригинальность. Это даст следующий результат —

sh-4.3$ main
X is not a Bool Type 

голец

Чар представляет персонажей. Все, что находится в одинарной кавычке, считается символом. В следующем коде мы изменили нашу предыдущую функцию fType (), чтобы она принимала значение Char и возвращала значение Char в качестве вывода.

Live Demo

fType :: Char-> Char 
fType x = 'K' 
main = do  
   let x = 'v' 
   print (fType x) 

Приведенный выше фрагмент кода вызовет функцию fType () со значением char, равным «v», но возвращает другое значение char, то есть «K». Вот его вывод —

sh-4.3$ main 
'K'

Обратите внимание, что мы не собираемся использовать эти типы явно, потому что Haskell достаточно умен, чтобы перехватить тип до того, как он будет объявлен. В последующих главах этого урока мы увидим, как различные типы и классы типов делают язык Haskell строго типизированным.

Класс эквалайзера

Класс EQ type — это интерфейс, который предоставляет функциональные возможности для проверки равенства выражения. Любой класс Type, который хочет проверить равенство выражения, должен быть частью этого класса EQ Type.

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

В следующем примере мы используем тип EQ для внутреннего использования операции «==» или «/ =».

Live Demo

main = do 
   if 8 /= 8 
      then putStrLn "The values are Equal" 
   else putStrLn "The values are not Equal"

Это даст следующий вывод —

sh-4.3$ main 
The values are not Equal 

Тип Орд Класс

Ord — это еще один интерфейсный класс, который дает нам функциональность упорядочения. Все типы, которые мы использовали до сих пор, являются частью этого интерфейса Ord . Как и интерфейс EQ, интерфейс Ord можно вызывать с помощью «>», «<», «<=», «> =», «сравнить».

Ниже приведен пример, где мы использовали «сравнить» функциональность этого класса типов.

Live Demo

main = print (4 <= 2) 

Здесь компилятор Haskell проверит, меньше ли 4 или равно 2. Так как это не так, код выдаст следующий вывод:

sh-4.3$ main 
False

Шоу

Функция Show имеет функцию печати аргумента в виде строки. Каким бы ни был его аргумент, он всегда печатает результат в виде строки. В следующем примере мы распечатаем весь список, используя этот интерфейс. «show» может использоваться для вызова этого интерфейса.

Live Demo

main = print (show [1..10]) 

Он выдаст следующий вывод на консоль. Здесь двойные кавычки указывают, что это значение типа String.

sh-4.3$ main 
"[1,2,3,4,5,6,7,8,9,10]" 

Читать

Интерфейс Read делает то же самое, что и Show, но не выводит результат в формате String. В следующем коде мы использовали интерфейс read для чтения строкового значения и преобразования его в значение Int.

Live Demo

main = print (readInt "12") 
readInt :: String -> Int 
readInt = read 

Здесь мы передаем переменную String («12») методу readInt, который, в свою очередь, возвращает 12 (значение Int) после преобразования. Вот его вывод —

sh-4.3$ main 
12

Enum

Enum — это другой тип класса Type, который включает последовательную или упорядоченную функциональность в Haskell. Этот класс Type может быть доступен с помощью таких команд, как Succ, Pred, Bool, Char и т. Д.

Следующий код показывает, как найти значение преемника 12.

Live Demo

main = print (succ 12) 

Это даст следующий результат —

sh-4.3$ main
13

ограниченный

Все типы, имеющие верхнюю и нижнюю границы, подпадают под этот класс типов. Например, данные типа Int имеют максимальную границу «9223372036854775807» и минимальную границу «-9223372036854775808».

Следующий код показывает, как Haskell определяет максимальную и минимальную границы типа Int.

Live Demo

main = do 
   print (maxBound :: Int) 
   print (minBound :: Int) 

Это даст следующий результат —

sh-4.3$ main
9223372036854775807
-9223372036854775808

Теперь попробуйте найти максимальную и минимальную границы типов Char, Float и Bool.

Num

Этот тип класса используется для числовых операций. Такие типы, как Int, Integer, Float и Double подпадают под этот класс Type. Посмотрите на следующий код —

Live Demo

main = do 
   print(2 :: Int)  
   print(2 :: Float) 

Это даст следующий результат —

sh-4.3$ main
2
2.0

интеграл

Интеграл можно рассматривать как подкласс класса Num Type. Класс Num Type содержит все типы чисел, тогда как класс Integral используется только для целых чисел. Int и Integer являются типами в этом классе типов.

плавучий

Как и Integral, Floating также является частью класса Num Type, но он содержит только числа с плавающей запятой. Следовательно, Float и Double подпадают под этот тип класса.

Класс пользовательского типа

Как и любой другой язык программирования, Haskell позволяет разработчикам определять пользовательские типы. В следующем примере мы создадим пользовательский тип и используем его.

Live Demo

data Area = Circle Float Float Float  
surface :: Area -> Float   
surface (Circle _ _ r) = pi * r ^ 2   
main = print (surface $ Circle 10 20 10 ) 

Здесь мы создали новый тип с именем Area . Далее мы используем этот тип для расчета площади круга. В приведенном выше примере «поверхность» — это функция, которая принимает Площадь в качестве входных данных и создает Float в качестве выходных данных.

Имейте в виду, что «данные» — это ключевое слово, и все пользовательские типы в Haskell всегда начинаются с заглавной буквы.

Это даст следующий результат —