I am trying to implement a "DrawEnv" type class indexed by a point type:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
class Monad m => DrawEnv p m where
box :: p -> p -> m ()
clear :: m ()
line :: p -> p -> m ()
type Pos = (Float,Float)
instance DrawEnv Pos IO where
box p0 p1 = putStrLn $ "Box " ++ show p0 ++ " " ++ show p1
clear = putStrLn "Clear"
line p0 p1 = putStrLn $ "Line " ++ show p0 ++ " " ++ show p1
draw :: DrawEnv Pos m => m ()
draw = do
clear
box (10.0,10.0) (100.0,100.0)
line (10.0,10.0) (100.0,50.0)
However GHC isn't happy:
Could not deduce (DrawEnv (t0, t1) m) arising from a use of `box'
from the context (DrawEnv Pos m)
bound by the type signature for draw :: DrawEnv Pos m => m ()
at Code/Interfaces3.hs:63:9-29
The type variables `t0', `t1' are ambiguous
Relevant bindings include
draw :: m () (bound at Code/Interfaces3.hs:64:1)
Note: there is a potential instance available:
instance DrawEnv Pos IO -- Defined at Code/Interfaces3.hs:56:10
In a stmt of a 'do' block: box (10.0, 10.0) (100.0, 100.0)
In the expression:
do { clear;
box (10.0, 10.0) (100.0, 100.0);
line (10.0, 10.0) (100.0, 50.0) }
In an equation for `draw':
draw
= do { clear;
box (10.0, 10.0) (100.0, 100.0);
line (10.0, 10.0) (100.0, 50.0) }
My question is why GHC doesn't accept this given the Pos constraint?
This class definition won't work, because the type of
cleardoesn't mention the type variablep, so it is impossible to instantiateclearwith a concrete type. Adding type signatures toboxorlinewon't help - evenclear :: IO ()will produce a type error.This could be fixed by adding a function dependency to your class:
Then the rest of your code compiles. Alternatively, you could split your class into two classes: