我正在尝试使用以下代码进行编译
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
)。如何将此信息明确告知编译器?
答案 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)