Haskell: class 实例的类型变量不明确
Haskell: type variable is ambiguous for class instance
import qualified Prelude
class List list where
toList :: list a -> [a]
fromList :: [a] -> list a
data Deque a = Deque [a] [a]
instance List Deque where
toList (Deque xs sy) = xs ++ reverse sy
fromList xs = Deque ys (reverse zs)
where (ys, zs) = splitAt (length xs `div` 2) xs
我收到如下复制的错误。似乎 GHCI 没有将 ys
检测为双端队列,而是检测为 class 列表的一般实例。
ghci> xs = [2, 3, 4]
ghci> ys = fromList xs
ghci> (Deque a b) = ys
ghci> toList (Deque a b)
[2,3,4]
ghci> toList ys
<interactive>:5:1: error:
* Could not deduce (List list0) arising from a use of `toList'
from the context: Num a
bound by the inferred type of it :: Num a => [a]
at <interactive>:5:1-9
The type variable `list0' is ambiguous
These potential instance exist:
instance [safe] List Deque -- Defined at main.hs:12:10
* In the expression: toList ys
In an equation for `it': it = toList ys
ghci> let xs = [2, 3, 4]
ghci> let ys = fromList ys
此时值具有可能的最通用类型:
ghci> :t xs
xs :: Num a => [a]
ghci> :t ys
ys :: (List list, Num a) => list a
没有 Deque
的提示,这是有道理的,因为您还没有提到任何双端队列。
但是那些变量保持不变,它们不会改变它们的类型!
之后
ghci> (Deque a b) = ys
ghci> toList (Deque a b)
[2,3,4]
您对 ys
的情况仍然相同,即
ghci> :t ys
ys :: (List list, Num a) => list a
当然,您曾经将 ys
用作双端队列,这是它的一种使用方式。但是作为多态,它也可以是任何其他 List
类型,并且 GHCi 不会做出任何猜测它应该是什么。但是你当然可以告诉它:
ghci> toList (ys :: Deque Int)
[2,3,4]
或更短
ghci> :set -XTypeApplications
ghci> toList @Deque ys
[2,3,4]
这是按设计工作的。当你写:
λ> ys = fromList xs
分配给 ys
的类型是:
λ> :t ys
ys :: (List list, Prelude.Num a) => list a
也就是说,ys
是一个多态值,可以“是”任何类型的 List
。
因此,当您将其绑定到特定模式时:
λ> Deque a b = ys
然后 ys
被实例化为 Deque
并且适当的值被绑定到 a
和 b
,但这不会使 ys
单态.也就是说,ys
并没有突然“变成”Deque
。相反,它仍然是一个多态值,可以重新绑定到其他 List
。例如,如果您还有一个普通旧列表的实例:
instance List [] where
toList = id
fromList = id
您可以在多种类型上实例化 ys
:
λ> xs = [2, 3, 4]
λ> ys = fromList xs
λ> Deque a b = ys -- instantiate as Deque
λ> c:d = ys -- instantiate as []
如果您觉得这很奇怪,请考虑:
λ> id "hello"
λ> id 'x'
两者都有效,即使第一次使用多态值 id :: a -> a
时,它被实例化为 String -> String
,而第二次使用时,它被实例化为 Char -> Char
。道理是一样的。
import qualified Prelude
class List list where
toList :: list a -> [a]
fromList :: [a] -> list a
data Deque a = Deque [a] [a]
instance List Deque where
toList (Deque xs sy) = xs ++ reverse sy
fromList xs = Deque ys (reverse zs)
where (ys, zs) = splitAt (length xs `div` 2) xs
我收到如下复制的错误。似乎 GHCI 没有将 ys
检测为双端队列,而是检测为 class 列表的一般实例。
ghci> xs = [2, 3, 4]
ghci> ys = fromList xs
ghci> (Deque a b) = ys
ghci> toList (Deque a b)
[2,3,4]
ghci> toList ys
<interactive>:5:1: error:
* Could not deduce (List list0) arising from a use of `toList'
from the context: Num a
bound by the inferred type of it :: Num a => [a]
at <interactive>:5:1-9
The type variable `list0' is ambiguous
These potential instance exist:
instance [safe] List Deque -- Defined at main.hs:12:10
* In the expression: toList ys
In an equation for `it': it = toList ys
ghci> let xs = [2, 3, 4]
ghci> let ys = fromList ys
此时值具有可能的最通用类型:
ghci> :t xs
xs :: Num a => [a]
ghci> :t ys
ys :: (List list, Num a) => list a
没有 Deque
的提示,这是有道理的,因为您还没有提到任何双端队列。
但是那些变量保持不变,它们不会改变它们的类型!
之后
ghci> (Deque a b) = ys
ghci> toList (Deque a b)
[2,3,4]
您对 ys
的情况仍然相同,即
ghci> :t ys
ys :: (List list, Num a) => list a
当然,您曾经将 ys
用作双端队列,这是它的一种使用方式。但是作为多态,它也可以是任何其他 List
类型,并且 GHCi 不会做出任何猜测它应该是什么。但是你当然可以告诉它:
ghci> toList (ys :: Deque Int)
[2,3,4]
或更短
ghci> :set -XTypeApplications
ghci> toList @Deque ys
[2,3,4]
这是按设计工作的。当你写:
λ> ys = fromList xs
分配给 ys
的类型是:
λ> :t ys
ys :: (List list, Prelude.Num a) => list a
也就是说,ys
是一个多态值,可以“是”任何类型的 List
。
因此,当您将其绑定到特定模式时:
λ> Deque a b = ys
然后 ys
被实例化为 Deque
并且适当的值被绑定到 a
和 b
,但这不会使 ys
单态.也就是说,ys
并没有突然“变成”Deque
。相反,它仍然是一个多态值,可以重新绑定到其他 List
。例如,如果您还有一个普通旧列表的实例:
instance List [] where
toList = id
fromList = id
您可以在多种类型上实例化 ys
:
λ> xs = [2, 3, 4]
λ> ys = fromList xs
λ> Deque a b = ys -- instantiate as Deque
λ> c:d = ys -- instantiate as []
如果您觉得这很奇怪,请考虑:
λ> id "hello"
λ> id 'x'
两者都有效,即使第一次使用多态值 id :: a -> a
时,它被实例化为 String -> String
,而第二次使用时,它被实例化为 Char -> Char
。道理是一样的。