×
Traktatov.net » Изучай Haskell во имя добра! » Читать онлайн
Страница 21 из 245 Настройки

. Наиболее часто используемая функция в классе типов >Show – это, собственно, функция >show. Она берёт значение, для типа которого определён экземпляр класса >Show, и представляет его в виде строки.

>ghci> show 3

>"3"

>ghci> show 5.334

>"5.334"

>ghci> show True

>"True"

Класс Read

Класс >Read – это нечто противоположное классу типов >Show. Функция >read принимает строку и возвращает значение, тип которого является экземпляром класса >Read.

>ghci> read "True" || False

>True

>ghci> read "8.2" + 3.8

>12.0

>ghci> read "5" – 2

>3

>ghci> read "[1,2,3,4]" ++ [3]

>[1,2,3,4,3]

Отлично. Но что случится, если попробовать вызвать >read>"4"?

>ghci> read "4"

>:1:0:

>    Ambiguous type variable `a' in the constraint:

>     `Read a' arising from a use of `read' at :1:0–7

>    Probable fix: add a type signature that fixes these type variable(s)

Интерпретатор GHCi пытается нам сказать, что он не знает, что именно мы хотим получить в результате. Заметьте: во время предыдущих вызовов функции >read мы что-то делали с результатом функции. Таким образом, интерпретатор GHCi мог вычислить, какой тип ответа из функции >read мы хотим получить.

Когда мы использовали результат как булево выражение, GHCi «понимал», что надо вернуть значение типа >Bool. А в данном случае он знает, что нам нужен некий тип, входящий в класс >Read, но не знает, какой именно. Давайте посмотрим на сигнатуру функции >read.

>ghci> :t read

>read :: (Read a) => String –> a

ПРИМЕЧАНИЕ. Идентификатор >String – альтернативное наименование типа >[Char]. Идентификаторы >String и >[Char] могут быть использованы взаимозаменяемо, но далее будет использоваться только >String, поскольку это удобнее и писать, и читать.

Видите? Функция возвращает тип, имеющий экземпляр класса >Read, но если мы не воспользуемся им позже, то у компилятора не будет способа определить, какой именно это тип. Вот почему используются явные аннотации типа. Аннотации типа – способ явно указать, какого типа должно быть выражение. Делается это с помощью добавления символов >:: в конец выражения и указания типа. Смотрите:

>ghci> read "5" :: Int

>5

>ghci> read "5" :: Float

>5.0

>ghci> (read "5" :: Float) * 4

>20.0

>ghci> read "[1,2,3,4]" :: [Int]

>[1,2,3,4]

>ghci> read "(3, 'a')" :: (Int, Char)

>(3, 'a')

Для большинства выражений компилятор может вывести тип самостоятельно. Но иногда он не знает, вернуть ли значение типа >Int или >Float для выражения вроде >read "5". Чтобы узнать, какой у него тип, язык Haskell должен был бы фактически вычислить >read "5".

Но так как Haskell – статически типизированный язык, он должен знать все типы до того, как скомпилируется код (или, в случае GHCi, вычислится). Так что мы должны сказать языку: «Эй, это выражение должно иметь вот такой тип, если ты сам случайно не понял!»

Обычно компилятору достаточно минимума информации, чтобы определить, значение какого именно типа должна вернуть функция >read. Скажем, если результат функции >read помещается в список, то Haskell использует тип списка, полученный благодаря наличию других элементов списка:

>ghci> [read "True" , False, True, False]

>[True, False, True, False]