QSpider
QSpider

Reputation: 567

Haskell: Malformed instance

I have problem for realisation of next in Haskell:

Type class:

class CArgumentableAttr a where
    expressArgumentAttr :: a -> (WidgetUI -> UI WidgetUI)

instance CArgumentableAttr (WidgetUI -> UI WidgetUI) where expressArgumentAttr a = a     

and realisation:

instance CArgumentableAttr (CSizeable b) => ((b, b, b, b) -> UI_StartingPoint -> WidgetUI -> UI WidgetUI) where expressArgumentAttr a = a (0, 0, 100, 50) UI_LT 
instance CArgumentableAttr (UI_StartingPoint -> WidgetUI -> UI WidgetUI) where expressArgumentAttr a = aUI_LT 

here:

class Show a => CSizeable a where
    showSize :: a -> String
instance CSizeable Int where
    showSize a = (show a) ++ "px"
instance CSizeable String where
    showSize a = if '%' `elem` a then a else (a ++ "%")

It use for:

bounds :: CSizeable a => (a, a, a, a) -> UI_StartingPoint -> WidgetUI -> UI WidgetUI
bounds (x, y, width, height) startingPoint widget =
    case startingPoint of 
        UI_LT -> applyStyleToWidget widget ("left:"  ++ (showSize x) ++ ";top:" ...

When compiling get the following error:
Malformed instance: CArgumentableAttr (CSizeable b) => ((b, b, b, b) -> UI_StartingPoint -> WidgetUI -> UI WidgetUI)

What can be done in this? Thank you!

Upvotes: 0

Views: 820

Answers (2)

ryachza
ryachza

Reputation: 4540

I think @Toxaris identified the issue, but I wanted propose some potential adjustments that may make things easier for you.

A few red flags for me are:

  1. There are CSizeable instances for both Int and String - this of course isn't wrong in any way taken in isolation
  2. The CSizeable Int instance always assumes pixels which prevents you from ever being able to, for example, numerically represent a percentage
  3. There is "parsing/checking" inside the CSizeable String instance
  4. There are "unit-less" numbers in the CArgumentableAttr instance

My thought is that perhaps CSizeable would be better as a plain data type instead of a class, or that you would have newtype wrappers instead of instances for Int and String.

As a data type:

data Size = Pixels Int | Percent Double | Literal String
instance Show Size where
  show (Pixels x) = show x ++ "px"
  show (Percent x) = show x ++ "%"
  show (Literal x) = x

instance CArgumentableAttr ((Size,Size,Size,Size) -> UI_StartingPoint -> WidgetUI -> UI WidgetUI) where expressArgumentAttr a = a (Pixels 0, Pixels 0, Pixels 100, Pixels 50) UI_LT
instance CArgumentableAttr (UI_StartingPoint -> WidgetUI -> UI WidgetUI) where expressArgumentAttr a = a UI_LT

bounds :: (Size,Size,Size,Size) -> UI_StartingPoint -> WidgetUI -> UI WidgetUI
bounds (x,y,width,height) startingPoint widget =
  case startingPoint of
    UI_LT -> applyStyleToWidget widget ("left:"  ++ show x ++ ";top:" ...

The newtype wrappers could look something like this:

newtype Pixels = Pixels Int
newtype Percent = Percent Double
newtype Literal = Literal String

instance CSizeable Pixels where showSize (Pixels x) = show x ++ "px"
instance CSizeable Percent where showSize (Percent x) = show x ++ "%"
instance CSizeable Literal where showSize (Literal x) = x

Upvotes: 4

Toxaris
Toxaris

Reputation: 7266

You use

instance CArgumentableAttr (CSizeable b) => ... where ...

but I think you want

instance (CSizeable b) => CArgumentableAttr ... where ...

instead.

Upvotes: 3

Related Questions