开发者

deducing type of multi-parameter type class

I'm trying to get the following code to compile

import IO

data MyInt = MyInt Int
data MyString = MyString String deriving Show

class Show b => MyClass a b where
    fn :: a -> b

instance MyClass MyInt MyString where
    fn (MyInt i) = MyString (show i)

myprint :: (MyClass a b) => a -> IO () 
myprint a = putStrLn $ show (fn a)

main = myprint (MyInt 3)

with ghc Main.hs -XMultiParamTypeClasses. However, the compiler cann开发者_开发问答ot deduce the type of the b type variable (which in this case is MyString). How can I explicitly tell this information to the compiler?


You've run afoul of the "open world" assumption. In this case, there's only one instance in scope that can satisfy the type constraints; but that's not a very declarative way to specify the meaning of myprint 3, is it? Given that instances can float in really from any module whatsoever, we can see how the open world assumption protects you from unanticipated changes of type/behaviour as modules are added or updated.

You could try functional dependencies or type families in this case.

class Show b => MyClass a b | a -> b where
  ...


To expand a bit on Jason's answer:

class Show b => MyClass a b | a -> b where
  ...

means that b functionally depends on a; that is, there can be no two instances of this class with the same a and different bs.


Instead of functional dependencies you can use type families which are equivalent to the former (at least theoretically) but seem to becoming more favorable form of type relationship definition. You can even avoid multi-parameter type classes in this case:

{-# LANGUAGE TypeFamilies #-}

data MyInt = MyInt Int
data MyString = MyString String deriving Show

class MyClass a where
    type Showable a :: *
    fn :: a -> Showable a

instance MyClass MyInt where
    type Showable MyInt = MyString
    fn (MyInt i) = MyString (show i)

myprint a = putStrLn $ show (fn a)

main = myprint (MyInt 3) 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜