Примите во внимание, что тип, экземпляр для которого вы пытаетесь создать, заменит параметр в декларации класса. Параметр >a
из декларации >class Eq a where
будет заменён конкретным типом при создании экземпляра; попытайтесь в уме заменить тип также и в декларациях функций. Сигнатура >(==) :: Maybe –> Maybe –> Bool
не имеет никакого смысла, но сигнатура >(==) :: (Eq m) => Maybe m –> Maybe m –> Bool
имеет. Впрочем, это нужно только для упражнения, потому что оператор >==
всегда будет иметь тип >(==) :: (Eq a) => a –> a –> Bool
независимо от того, какие экземпляры мы порождаем.
О, и ещё одна классная фишка! Если хотите узнать, какие экземпляры существуют для класса типов, вызовите команду >: info
в GHCi. Например, выполнив команду >:info Num
, вы увидите, какие функции определены в этом классе типов, и выведете список принадлежащих классу типов. Команда >:info
также работает с типами и конструкторами типов. Если выполнить >:info Maybe
, мы увидим все классы типов, к которым относится тип >Maybe
. Вот пример:
>ghci> :info Maybe
>data Maybe a = Nothing | Just a -- Defined in Data.Maybe
>instance Eq a => Eq (Maybe a) -- Defined in Data.Maybe
>instance Monad Maybe -- Defined in Data.Maybe
>instance Functor Maybe -- Defined in Data.Maybe
>instance Ord a => Ord (Maybe a) -- Defined in Data.Maybe
>instance Read a => Read (Maybe a) -- Defined in GHC.Read
>instance Show a => Show (Maybe a) -- Defined in GHC.Show
В языке JavaScript и в некоторых других слабо типизированных языках вы можете поместить в оператор >if
практически любые выражения. Например, все следующие выражения правильные:
>if (0) alert("ДА!") else alert("НЕТ!")
>if ("") alert ("ДА!") else alert("НЕТ!")
>if (false) alert("ДА!") else alert("НЕТ!)
и все они покажут >НЕТ!"
.
Если вызвать
>if ("ЧТО") alert ("ДА!") else alert("НЕТ!")
мы увидим >"ДА!"
, так как язык JavaScript рассматривает непустые строки как вариант истинного значения.
Несмотря на то, что строгое использование типа >Bool
для булевских выражений является преимуществом языка Haskell, давайте реализуем подобное поведение. Просто для забавы. Начнём с декларации класса:
>class YesNo a where
> yesno :: a –> Bool
Довольно просто. Класс типов >YesNo
определяет один метод. Эта функция принимает одно значение некоторого типа, который может рассматриваться как хранитель некоей концепции истинности; функция говорит нам, истинно значение или нет. Обратите внимание: из того, как мы использовали параметр >a
в функции, следует, что он должен быть конкретным типом.
Теперь определим несколько экземпляров. Для чисел, так же как и в языке JavaScript, предположим, что любое ненулевое значение истинно, а нулевое – ложно.