: спринт для полиморфных значений?

Мне интересно, почему :sprint сообщает xs = _ в этом случае:

 Prelude> xs = map (+1) [1..10] Prelude> length xs 10 Prelude> :sprint xs xs = _ 

но не в этом случае:

 Prelude> xs = map (+1) [1..10] :: [Int] Prelude> length xs 10 Prelude> :sprint xs xs = [_,_,_,_,_,_,_,_,_,_] 

Примечание. Я запускаю ghci с -XNoMonomorphismRestriction . Имеет ли это отношение к тому, что тип xs является полиморфным в первом случае, но не во втором? Я хотел бы знать, что происходит внутри страны.

Суть в том, что с полиморфным xs он имеет вид формы

 xs :: Num a => [a] 

typeclasses под капотом – действительно просто функции, они берут дополнительный аргумент, который GHC автоматически заполняет, содержащий запись о функциях typeclasses. Таким образом, вы можете думать о xs имеющем тип

 xs :: NumDict a -> [a] 

Поэтому, когда вы запускаете

 Prelude> length xs 

Он должен выбрать некоторое значение для a и найти соответствующее значение NumDict . IIRC он заполнит его Integer , так что вы на самом деле вызываете функцию и проверяете длину результирующего списка.

Когда вы тогда :sprint xs , вы снова заполните этот аргумент, на этот раз со свежей переменной типа. Но дело в том, что вы получаете совершенно другой список, вы дали ему другой NumDict поэтому он не был вынужден каким-либо образом, когда вы называли length раньше.

Это сильно отличается от явно monoморфного списка, так как там действительно есть только один список, есть только одно значение, чтобы заставить так, когда вы вызываете длину, он заставляет его для всех будущих использования xs .

Чтобы сделать это немного яснее, рассмотрите код

 data Smash a = Smash { smash :: a -> a -> a } -- ^ Think of Monoids intSmash :: Smash Int intSmash = Smash (+) listSmash :: Smash [a] listPlus = Smash (++) join :: Smash a -> [a] -> a join (Smash s) xs = foldl1' s xs 

Это действительно то, что типа classов, как под капотом, GHC будет автоматически заполнить этот первый Smash a аргумент для нас. Теперь ваш первый пример подобен join , мы не можем делать какие-либо предположения о том, какой результат будет, когда мы применяем его к разным типам, но ваш второй пример больше похож на

 join' :: [Int] -> Int join' = join intSmash 
  • Объяснение «привязка узла»
  • Список различных типов?
  • Настройка Eclipse для компиляции Haskell с плагином EclipseFP
  • Существуют ли объявляемые имена для обычных операторов Haskell?
  • Почему 3 и x (которые были назначены 3) имеют разные предполагаемые типы в Haskell?
  • Что такое «|» в определении classа Haskell?
  • Есть ли список расширений GHC, которые считаются «безопасными»?
  • IO не работает при использовании getLine и putStr
  • У Haskell есть рекурсивная оптимизация?
  • Scala: Как определить «общие» параметры функции?
  • Заявки сочиняют, монады не делают
  • Давайте будем гением компьютера.