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 []
问题
NestedList
定义更改为接受空List
吗?如果是这样,我该怎么做。它很混乱。答案 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])
。