推导出多参数类型的类型

时间:2010-07-15 05:53:03

标签: haskell types typeclass

我正在尝试使用以下代码进行编译

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)

ghc Main.hs -XMultiParamTypeClasses。但是,编译器无法推断出b类型变量的类型(在本例中为MyString)。如何将此信息明确告知编译器?

3 个答案:

答案 0 :(得分:5)

你违背了“开放世界”的假设。在这种情况下,范围中只有一个实例可以满足类型约束;但这不是一个非常声明的方式来指定myprint 3的含义,是吗?鉴于实例可以真正从任何模块中浮出,我们可以看到开放世界假设如何在模块添加或更新时保护您免受类型/行为的意外更改。

在这种情况下,您可以尝试功能依赖项或键入系列。

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

答案 1 :(得分:3)

为了扩大杰森的答案:

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

表示b在功能上取决于a;也就是说,此类的两个实例不能具有相同的a和不同的b

答案 2 :(得分:3)

您可以使用与前者相同的类型族(至少在理论上),而不是功能依赖性,但似乎成为更有利的类型关系定义形式。 在这种情况下,您甚至可以避免多参数类型类:

{-# 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)