Reputation: 407
I would like to associate my typeclass with the type, which is an instance of the certain typeclass (Show
for example).
Solution with the fundeps:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
class (Show msg) => Handler msg h | h -> msg where
handle :: h -> msg -> String
So I can implement the Handler
, which will handle only data of associated type.
data IntHandler = IntHandler
instance Handler Int IntHandler where -- OK.
handle _ x = show x data Foo = Foo
handle IntHandler 1 -- OK.
handle IntHandler "1" -- Fail.
data Foo = Foo
data FooHandler = FooHandler
instance Handler Foo FooHandler where -- Fails to typecheck, Foo is not an instance of Show
handle _ _ = "failed"
The question: how to achieve the same functionality with the type families?
Let's try and declare the Handler'
class and its implementation for IntHandler'
type:
{-# LANGUAGE TypeFamilies #-}
class Handler' h where
type Msg h
handle' :: h -> Msg h -> String
data IntHandler' = IntHandler'
instance Handler' IntHandler' where
type Msg IntHandler' = Int
handle' _ x = show x
Good, this type checks. Now let's create implementation for the Foo
type:
data Foo = Foo
data FooHandler' = FooHandler'
instance Handler' FooHandler where
type Msg FooHanler' = Foo
handle' _ _ = "this won't fail"
But it also typechecks, but I want to prevent it to type check. So, how to constrain the result of the type function Msg
?
Upvotes: 3
Views: 746
Reputation: 407
As @Carl is pointed out, it's pretty obvious:
class (Show (Msg h)) => Handler h where
It was my silly mistake... Just had to enable FlexibleContexts
.
Upvotes: 3