2014-12-03 36 views
3

首先,我的背景是C++,所以尽量不要让我失望过度。Haskell - 多态类型的演绎秀

在这个人为的例子,我试图定义一个多态类型,看起来像这样:

data T x y 
    = Cons1 x 
    | Cons2 y 
    | Neither 
    deriving (Show) 

我想持有任一类型x,类型y或两者都不值的数据类型。各种各样的Maybe a。当我尝试这样做:

main = do 
    let v = Cons1 1 
    putStrLn (show v) 

有些含糊出现了:

No instance for (Show y0) arising from a use of `show' 
The type variable `y0' is ambiguous 
Note: there are several potential instances: 
    instance (Show x, Show y) => Show (T x y) 
    -- Defined at C:\Projects\Private\Haskell\Play\play.hs:14:27 
    instance Show Double -- Defined in `GHC.Float' 
    instance Show Float -- Defined in `GHC.Float' 
    ...plus 25 others 
In the first argument of `putStrLn', namely `(show t)' 
In a stmt of a 'do' block: putStrLn (show t) 
In the expression: 
    do { let t = Cons1 1; 
     putStrLn (show t) } 

这是为什么?为什么有歧义? 1Cons1 1是我所了解的一个数字,它全部来源于Show。我想,构造函数本身充当鉴别器,制作Cons1 1 /= Cons2 1

回答

4

随着Cons1 1编译器只能够推导data T x yx类型,也没有办法来推断yx变成Num a,但y呢?你需要在这种情况下,手动指定:

main = do 
    let v = (Cons1 1 :: T Int Int) -- just an example 
    putStrLn (show v) 

在某些情况下,如果你会使用明确的功能类型,编译器将能够自动地推断出它。但在这种情况下,它确实没有提示。

这与Nothing自己模糊不清。它是Maybe String,Maybe Int,Maybe Double,...?

+0

如果我注释掉打印行,编译器会接受它。编译器如此懒惰,直到我调用show时才会生成show函数?另外,你将如何模拟这种类型?我感觉我的例子是糟糕的形式! – 2014-12-03 21:46:06

+0

@JörgenSigvardsson奇怪。它应该生成一个“do'块中的最后一个语句必须是表达式”编译错误“。你的类型不是一个糟糕的形式。 '或者'的建模方式几乎是相同的(每种类型有两种类型和两种类型的构造函数)。 – Shoe 2014-12-03 22:13:25

+0

我用空字符串替换了打印的表达式,而不是删除。对此感到困惑不已。 – 2014-12-03 22:16:21