Покажи мне, как читать

Классы типов Show и Read предназначены для сущностей, которые могут быть преобразованы в строки и из строк соответственно. Как и для класса Eq, все типы в конструкторе типов также должны иметь экземпляры для классов Show и/или Read, если мы хотим получить такое поведение. Давайте сделаем наш тип данных Person частью классов Show и Read:

data Person = Person { firstName :: String

                     , lastName :: String

                     , age :: Int

                     } deriving (Eq, Show, Read)

Теперь мы можем распечатать запись на экране:

ghci> mikeD

Person {firstName = "Michael", lastName = "Diamond", age = 43}

ghci> "mikeD is: " ++ show mikeD

"mikeD is: Person {firstName = "Michael", lastName = "Diamond", age = 43}"

Если бы мы попытались распечатать запись до того, как предусмотрели для типа Person экземпляры класса Show, язык Haskell пожаловался бы на то, что он не знает, как представить запись в виде строки. Но после того как мы определили экземпляр класса Show, всё проясняется.

Класс Read в чём-то является обратным классом типов для класса Show. Класс Show служит для преобразования значений нашего типа в строку, класс Read нужен для преобразования строк в значения типа. Запомните, что при использовании функции чтения мы должны явно аннотировать тип возвращаемого значения. Если не указать тип результата явно, язык Haskell не сможет угадать, какой тип мы желали бы получить. Чтобы это проиллюстрировать, поместим в файл строку, представляющую некоторого человека, а затем загрузим файл в GHCi:

mysteryDude = "Person { firstName ="Майкл"" ++

                     ", lastName ="Даймонд"" ++

                     ", age = 45}"

Для большей «читабельности» мы разбили строку на несколько фрагментов. Если теперь необходимо вызвать с этой строкой функцию read, то потребуется указать тип, который мы ожидаем получить:

ghci> read mysteryDude :: Person

Person {firstName = "Майкл", lastName = "Даймонд", age = 45}

Если далее в программе мы используем результат чтения таким образом, что язык Haskell сможет вывести его тип, мы не обязаны использовать аннотацию типа.

ghci> read mysteryDude == mikeD

True

Так же можно считывать и параметризованные типы, но при этом следует явно указывать все типы-параметры.

Если мы попробуем сделать так:

ghci> read "Just 3" :: Maybe a

то получим сообщение об ошибке: Haskell не в состоянии определить конкретный тип, который следует подставить на место типовой переменной a. Если же мы точно укажем, что хотим получить Int, то всё будет прекрасно:

ghci> read "Just 3" :: Maybe Int

Just 3