由于使用'print'而没有(Show a0)的实例类型变量`a0'是不明确的

时间:2013-09-04 13:47:36

标签: haskell

data NestedList a = Elem a | List [NestedList a]
flatten :: NestedList a -> [a]
flatten (Elem element) = [element]
flatten (List []) = []
flatten (List (first:rest)) = flatten first ++ flatten (List (rest))
main = print $ flatten $ List []

我在haskell中写了上面看到的代码。当我使用任何其他参数执行此操作时,例如

main = print $ flatten $ List [Elem 1, Elem 2]
main = print $ flatten $ Elem 1

它给出了

[1, 2]
[1]

分别

当我使用空列表执行它时失败。

main = print $ flatten $ List []

错误消息

No instance for (Show a0) arising from a use of `print'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance Show Double -- Defined in `GHC.Float'
  instance Show Float -- Defined in `GHC.Float'
  instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
    -- Defined in `GHC.Real'
  ...plus 23 others
In the expression: print
In the expression: print $ flatten $ List []
In an equation for `main': main = print $ flatten $ List []

问题

  1. 为什么会失败,我该如何解决?
  2. 我应该将NestedList定义更改为接受空List吗?如果是这样,我该怎么做。它很混乱。

4 个答案:

答案 0 :(得分:16)

列表类型是多态的。由于您不提供元素,只提供空列表构造函数[],因此无法推断出它是什么列表类型。

是:[] :: [Int]

[] :: [Maybe (Either String Double)]。谁该说?

你是。提供一个类型注释来解析多态,然后GHC可以调度到正确的show实例。

E.g。

main = print $ flatten $ List ([] :: [Int])

答案 1 :(得分:9)

要在这里添加答案,你可能会反对“但是我的清单包含什么类型的东西有什么关系呢?它里面没有任何东西!”

嗯,首先,很容易构建一个不清楚列表是否为空的情况,无论如何类型检查讨厌查看,它只想看看类型。这样可以使事情变得更简单,因为这意味着在处理值时,您可以确定已经知道所有类型。

其次,它实际上确实它是什么类型的列表,即使它是空的:

ghci> print ([] :: [Int])
[]
ghci> print ([] :: [Char])
""

答案 2 :(得分:8)

问题是编译器无法知道flatten $ List []的类型。尝试自己确定类型,对于某些[a],您会看到a,而print要求其参数为Show的实例,{{1如果[a]Show的实例,则是a的实例。即使您的列表为空,因此Show上不需要任何约束来表示a,编译器也无法知道。

因此,放置显式类型注释(对于存在[]实例的任何类型)应该有效:

Show

main = print $ flatten $ List ([] :: [NestedList Int])

main = print $ flatten $ List ([] :: [NestedList ()])

答案 3 :(得分:3)

[]可以是浮点数,字符串,布尔值或实际上任何类型的列表。因此,print不知道要使用哪个show实例。

按照错误消息说明并提供显式类型,如([] :: [Int])