Чому Haskell не може уникнути повторного оцінювання без обмеження мономорфізму?


14

Я щойно закінчив учінняааскелл на днях, і я намагався зрозуміти обмеження мономорфізму, як описано в Haskell Wiki . Я думаю, що я розумію, як ЗМ може запобігти повторному оцінюванню, але я не розумію, чому цих повторних оцінок неможливо уникнути набагато більш простими способами.

Я маю на увазі конкретний приклад, який використовується вікі:

f xs = (len,len)
  where
    len = genericLength xs

де genericLengthє тип Num a => [b] -> a.

Очевидно, що genericLength xsдля їх оцінки потрібно обчислити лише один раз (len,len), оскільки це та сама функція з тими ж аргументами. І нам не потрібно бачити жодних викликів, fщоб це знати. То чому б Haskell не може зробити цю оптимізацію, не запровадивши таке правило, як MR?

Обговорення на цій сторінці вікі говорить про те, що це має щось Numспільне з тим, що це тип класу, а не конкретний тип, але навіть якщо це не стане очевидним під час компіляції, що чиста функція повертає те саме значення, -і, отже, той самий конкретний тип Num - коли даються однакові аргументи двічі?

Відповіді:


11

Це та сама назва функції, з тими ж аргументами, але потенційно різними типами повернення та реалізацією, оскільки це поліморфно. Це означає, що якщо він викликається в контексті, який очікує (Int, MyWeirdCustomNumType)тип повернення, він повинен оцінювати його двічі, тому що реалізація (+)в програмі Intповністю відрізняється від реалізації (+)в MyWeirdCustomNumType. Вам потрібно запустити фізично інший код в якийсь момент.

Ось чому важливо, що Numце клас типу. Це означає, що у вас є різні реалізації для різних типів. Це також означає, що якщо fвін знаходиться в бібліотеці, він не знає під час компіляції про всі комбінації типів, які, можливо, потрібно буде повернути.

Отже, так, вам потрібно переглянути виклики, fщоб знати, які типи повернення використовувати. Більшу частину часу ви б очікували, що вони будуть однаковими, саме тому вони встановили обмеження мономорфізму за замовчуванням. Його можна вимкнути в тих рідкісних випадках, коли цього не зробите. На практиці програмісти так чи інакше не залишають подібні ситуації.


Я не розглядав можливості f [] :: (Int, Float). Тепер це має ідеальний сенс. Дякую.
Іксрек

1
It's the same function name, with the same arguments, but potentially different return types and implementations, because it's polymorphic.Я думаю, що кращий спосіб поглянути на це полягає в тому, що екземпляр typeclass фактично є додатковим аргументом, genericLengthі компілятор не переконаний, що це однакові аргументи в обох викликах.
Doval

Питання швидкої сторони Якщо MonomorphismRestriction вимкнено, але пізніше ви зробили щось на кшталт, a = uncurry (==) $ f [1, 2, 3]чи вдасться оптимізувати цей сайт виклику лише [1, 2, 3]один раз перевірити довжину ? Якщо так, то я дуже розгублений у тому, що саме обмеження мономорфізму купує вас, якщо ні, то чому б ні?
крапка з комою
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.