[英]Type signature comfusion in Haskell
所以我的代码中有这个 function
type Player = Char
choose :: Player -> a -> a -> a
choose p a b
| p == 'X' = a
| p == 'O' = b
在某一时刻,它是这样使用的
(choose p (+) (-)) 5 5
我可以清楚地看到它在 (+) 或 (-) function 之间进行选择,然后将其应用于 5 和 5。事实上,我什至自己在 GHCI 中对其进行了测试。
但是,这里是上述函数的类型签名
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
我根本不明白这种类型的签名如何通过 function 来选择。 不应该选择有这样的类型签名吗?
choose :: Num a => Player -> (a -> a -> a) -> (a -> a -> a) -> (a -> a -> a)
有人可以帮我解释一下吗?
那些是不一样a
。
choose
的a
是签名与(+)
和(-)
a
签名不同。 它们碰巧有相同的名称,但它们是单独的类型变量,彼此完全不相关。
因此,为了消除混淆,让我们重命名其中一个:
choose :: Player -> x -> x -> x
(-) :: Num a => a -> a -> a
(+) :: Num a => a -> a -> a
现在,如果我们应用choose p (+) (-)
,如果我们设置x ~ (a -> a -> a)
就可以了
您需要记住,类型变量可以在每次使用时实例化,并且可以实例化为本身具有多个部分的复杂类型 A function 类型,如a -> a -> a
与替代类型变量一样好Int
或[Char]
或(Double, Double)
等。
因此,如果我们将a
类型变量实例化为Char
,我们会得到:
-- here choose is used as Player -> Char -> Char -> Char
choose p 'X' 'O'
如果我们将a
类型变量实例化为a -> a -> a
,那么我们会得到:
-- here choose is used as Num a => Player -> (a -> a -> a) -> (a -> a -> a) -> (a -> a -> a)
choose p (+) (-)
因此,无论何时你看到一个函数的类型接受一个参数或返回一个简单类型变量的结果,比如id:: a -> a
,这并不意味着你不能将它应用到函数中 看起来更复杂的东西,比如(t -> Int -> [t]) -> (t -> Int -> [t])
是您可以使用简单类型(如a -> a
for)的完整通用性的特定示例。
您需要学习查看 function 类型不是特别特别; 它们只是存在的多种类型中的一种,任何声称适用于所有类型的东西都必须适用于 function 类型。
还要记住,两个不同类型签名中的类型变量在不同的范围内。 原始choose:: Player -> a -> a -> a
中的变量a
与(+):: Num a => a -> a -> a
中的变量a
甚至是choose:: Num a => Player -> (a -> a -> a) -> (a -> a -> a) -> (a -> a -> a)
中的变量不同。 choose:: Num a => Player -> (a -> a -> a) -> (a -> a -> a) -> (a -> a -> a)
。 如果它有帮助,那么在您解决问题时,您始终可以重命名您正在考虑的所有类型签名中的变量(然后可以选择重命名最后一个变量中的变量以匹配 GHC 等外部源)。 例如,我可以通过说我正在考虑(+):: Num b => b -> b -> b
来避免混淆,然后将其替换a
Player -> a -> a -> a
中的 a 以获得Num b => Player -> (b -> b -> b) -> (b -> b -> b) -> (b -> b -> b)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.