: спринт для полиморфных значений?
Мне интересно почему :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
полиморфен в первом случае, но не во втором? Я хотел бы знать, что происходит внутри.
1 ответ
Суть в том, что с полиморфным xs
это имеет вид формы
xs :: Num a => [a]
Классы типов в действительности являются просто функциями, они принимают дополнительный аргумент, который автоматически заполняет GHC, который содержит запись функций классов. Так что вы можете думать о xs
имея тип
xs :: NumDict a -> [a]
Поэтому, когда вы бежите
Prelude> length xs
Он должен выбрать какое-то значение для a
и найти соответствующий NumDict
значение. IIRC это заполнит его Integer
Таким образом, вы фактически вызываете функцию и проверяете длину полученного списка.
Когда ты тогда :sprint
xs
Вы снова заполняете этот аргумент, на этот раз новой переменной типа. Но дело в том, что вы получаете совершенно другой список, вы дали ему другой NumDict
так что это не обязательно, когда вы позвонили length
до.
Это сильно отличается от явно мономорфного списка, так как на самом деле там только один список, есть только одно значение для принудительного использования, поэтому, когда вы вызываете 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