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

Мне интересно почему :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Таким образом, вы фактически вызываете функцию и проверяете длину полученного списка.

Когда ты тогда :sprintxsВы снова заполняете этот аргумент, на этот раз новой переменной типа. Но дело в том, что вы получаете совершенно другой список, вы дали ему другой 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
Другие вопросы по тегам