Проблема в том, что подпись типа area
:
area :: (Num b) => a -> Area b
То, что он говорит, это «дай мне a
, и я дам тебе Area b
для любого b
, который ты хочешь; ты можешь выбрать». Так, например, я мог бы дать area
Integer
и ожидать обратно Area Double
. Очевидно, это не то, что вы хотите!
В этом случае ошибка возникает из-за того, что вы используете x*y
, который имеет тип a , когда ожидается b - вы должны указать значение, которое работает для любой числовой тип b , но вы даете значение, которое работает только для одного ( a ).
Если вы изменили тип area
на a -> Area Integer
или что-то подобное, то это сработало бы. Однако у меня есть ощущение, что вы хотите, чтобы instance мог указывать тип области. Для этого вам нужно использовать языковое расширение под названием семейства типов :
{-# LANGUAGE TypeFamilies #-}
class (Num (AreaComponent a)) => Shape a where
type AreaComponent a
area :: a -> Area (AreaComponent a)
instance (Num a) => Shape (Rectangle a) where
type AreaComponent (Rectangle a) = a
area (Rectangle x y unit) = Area (x*y) unit
Это говорит о том, что для каждого типа a , который является экземпляром Shape
, существует связанный тип AreaComponent a
, представляющий тип каждого компонента его области. Этот тип должен быть экземпляром Num
по определению Shape
.
Еще одна вещь, которую вы можете сделать, если все ваши фигуры принимают числовой параметр типа, - это сделать так, чтобы экземпляры были для конструкторов типов каждой фигуры, а не для полных типов фигуры:
class Shape sh where
area :: (Num a) => sh a -> Area a
instance Shape Rectangle where
area (Rectangle x y unit) = Area (x*y) unit