2014-02-03 5 views
12

мне интересно, почему :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 является полиморфным в первом случае, но не во втором? Я хотел бы знать, что происходит внутри страны.

+4

Это именно такой путаницы в ограничение мономорфизма предназначено для предотвращения, поэтому вы должны * определенно * прочитать страницу [wiki на нем] (http://www.haskell.org/haskellwiki/Monomorphism_restriction). –

ответ

9

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

xs :: Num a => [a] 

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

xs :: NumDict a -> [a] 

Так что, когда вы запускаете

Prelude> length xs 

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

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

Это очень отличается от явно мономорфного списка, так как там действительно есть только один список, есть только одно значение, чтобы заставить так, когда вы вызываете длину, он заставляет его для всех будущих использования 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 

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

join' :: [Int] -> Int 
join' = join intSmash 
+0

Это объяснение трудно понять. – mljrg

+0

@mljrg Любая конкретная деталь? – jozefg

+0

Поскольку внутренняя работа классов и предметов NumDict не детализирована и приведена в качестве примера, трудно следовать вашему ответу. Можете ли вы дать ссылку, где это вещество хорошо объяснено? В любом случае кажется, что: sprint страдает от некоторых побочных эффектов реализации, что иронично для Haskell ... Обратите внимание, что если 'length xs' должен перемещаться по всему списку, тогда': sprint' всегда должен печатать '[_, _, ...] 'независимо от типа элементов в списке. Есть ошибка ... – mljrg

Смежные вопросы