Попробуйте мысленно (или с помощью текстового редактора) заполнить типы, указанные в определении класса, типом, который вы использовали в экземпляре.
Из:
class Print a where
print :: a -> String
а также
data A t = A t
мы хотим
instance Print A
Итак, заменив a
в определении класса типа на A
, которое мы называем экземпляром, мы получим следующее:
class Print A where
print :: A -> String
О-о. A -> String
не имеет смысла как тип, поскольку стрелка типа функции принимает тип слева и тип справа и дает вам тип функции. Но A
не является типом, так как вы объявили A
с data A t
; A t
— это тип для любого типа t
, но A
— это конструктор типа. Он может создать тип, если вы примените его к типу, но сам A
представляет собой нечто иное. Таким образом, вы можете сделать A t
экземпляром Print
, но не самим A
.
Так почему же instance Functor IO
сработало? Давайте посмотрим на определение класса:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Теперь давайте попробуем заменить IO
на f
:
class Functor IO where
fmap :: (a -> b) -> IO a -> IO b
В конечном итоге IO
s применяются к параметрам типа, так что все работает. Здесь мы столкнулись бы с проблемами, если бы попытались сделать конкретный тип, такой как Int
или A t
, экземпляром Functor
.
person
Ben
schedule
26.10.2012