Это важно различать полиморфизм объектно-ориентированные языки и полиморфизм в Haskell. OO polymorphism is covariant, while Haskell's parametric polymorphism is contravariant.
Что это означает: в ОО-языке, если у вас есть
class A {...}
class B: A {...}
т.е. A
является суперкласс B
, то любое значение типа B
также значение типа A
. (Обратите внимание, что любой конкретный значение на самом деле не полиморфный, но имеет конкретный тип!) Таким образом, если у вас
class Num {...}
class Fractional: Num {...}
то значение Fractional
действительно может быть использовано в качестве значения Num
. Это примерно то, что означает ковариант: любое значение подкласса is also a superclass value; иерархия значений идет в том же направлении, что и иерархия типов.
В Haskell, class
es разные.Нет такой вещи, как «значение типа Num
», только значения конкретных типов a
. То, что типа может быть в классе Num
.
В отличии от ОО-языков, значение как 1 :: Num a => a
является полиморфными: он может взять на себя весь тип требований охраны окружающей среды, при условии, что тип в Num
классе. (На самом деле этот синтаксис только обсчитывать для 1 :: ∀ a . Num a => a
, следует читать как «для всех типов a
, вы можете иметь значение 1
типа a
). Например,
Prelude> let x = 1 :: Num a => a
Prelude> x :: Int
1
Prelude> x :: Double
1.0
Вы также можете дать x
более конкретное ограничение Fractional
, так как это подкласс Num
. Это просто ограничивает какой тип полиморфного значение может быть реализовано на:
Prelude> let x = 1 :: Fractional a => a
Prelude> x :: Int
<interactive>:6:1:
No instance for (Fractional Int) arising from a use of ‘x’
...
Prelude> x :: Double
1.0
потому Int
не дробный типа.
Таким образом, полиморфизм Haskell является контравариантным: полиморфные значения, ограниченные суперклассом, также могут быть ограничены подклассом, но не наоборот. В частности, вы можете, очевидно,
Prelude> let y = 1.0 :: Fractional a => a
(y
таким же, как x'
), но вы не можете обобщить это y' = 1.0 :: Num a => a
. Что хорошо, как заметил Инго, поскольку в противном случае можно было бы сделать
Prelude> 3.14159 :: Int
????
спасибо @chi. имеет смысл, когда вы так выразились :) поэтому '1 :: Num a => a' имеет значение true для любого' a', который является экземпляром 'Num', а' 1.0' - нет. – rodic
@rodic Да. Теоретически разработчики Haskell могли бы утверждать, что '1.0' обрабатывается так, как если бы это было' 1', но на практике было бы ужасно запутанно обнаруживать, что в данном контексте тип '1.0' проверяет, но' 1.5' делает не. Таким образом, '1.0' разрешалось только представлять значения типов в классе« Fractional ». – chi
Да, у меня было какое-то поплавок, когда я писал 1.0. но теперь я понимаю, что мой первоначальный вопрос можно переписать так: почему '1 :: a' не компилируется. Большое спасибо за помощь. – rodic