Як заголовок: як є гарантія оцінювання блоку повернення функції Haskell? Можна подумати, що немає необхідності проводити будь-яку оцінку в такому випадку, компілятор міг би замінити всі такі виклики на негайне ()
значення, якщо немає явних запитів на суворість, і в цьому випадку код може вирішити, чи слід повернення ()
або дно.
Я експериментував з цим у GHCi, і, схоже, відбувається навпаки, тобто така функція, схоже, оцінюється. Дуже примітивний приклад був би
f :: a -> ()
f _ = undefined
Оцінювання f 1
кидає помилку через наявність undefined
, тому певна оцінка точно відбувається. Не ясно, наскільки глибоко йде оцінка; іноді, схоже, йдеться настільки глибоко, як це необхідно для оцінки всіх дзвінків до функцій, що повертаються ()
. Приклад:
g :: [a] -> ()
g [] = ()
g (_:xs) = g xs
Цей код замикається на невизначений термін, якщо він представлений g (let x = 1:x in x)
. Але потім
f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()
може бути використаний для показу, що h (f 1)
повертається ()
, тому в цьому випадку оцінюються не всі одиничні вираження під вираженнями. Яке тут загальне правило?
ЕТА: звичайно, я знаю про лінь. Я запитую, що заважає авторам-компіляторам зробити цей конкретний випадок ще лінивішим, ніж це можливо.
ETA2: підсумок прикладів: GHC, як видається, трактує ()
точно так само, як і будь-який інший тип, тобто як би виникає питання про те, яке регулярне значення, що населяє тип, має бути повернуто з функції. Те, що існує лише одне таке значення, схоже, не використовується (ab), що використовується алгоритмами оптимізації.
ETA3: коли я кажу Haskell, я маю на увазі Haskell як визначено у звіті, а не Haskell-H-in-GHC. Здається, це припущення, яке не поділяється так широко, як я уявляв (це було «на 100% читачів»), або я, певно, міг би сформулювати більш чітке питання. Незважаючи на це, я шкодую, що змінив назву питання, оскільки спочатку запитував, які існують гарантії для такої функції.
ETA4: Здавалося б, це питання пробігло свій шлях, і я вважаю його без відповіді. (Я шукав функцію "закритого запитання", але знайшов лише "відповідь на власне запитання", і оскільки на нього не можна відповісти, я не пішов по цьому маршруту.) Зі Звіту ніхто не підніс нічого, що вирішило б це так чи інакше , яку я спокусив трактувати як категоричну, але не певну відповідь "немає гарантії для мови як такої". Все, що ми знаємо, - це те, що поточна реалізація GHC не пропустить оцінку такої функції.
Я зіткнувся з фактичною проблемою під час перенесення програми OCaml в Haskell. Початковий додаток мав взаємно рекурсивну структуру багатьох типів, і код оголошував ряд функцій, викликаних assert_structureN_is_correct
N в 1..6 або 7, кожна з яких повертала одиницю, якщо структура справді була правильною, і кинула виняток, якщо її не було . Крім того, ці функції називали один одного, коли вони розкладали умови правильності. У Haskell це краще вирішувати, використовуючи Either String
монаду, тому я її так переписав, але питання як теоретичне питання залишилося. Дякую за всі матеріали та відповіді.
f 1
"замінено" на undefined
всі випадки.
... -> ()
може 1) закінчуватись і повертатись ()
, 2) закінчуватися з помилкою виключення / часу виконання і нічого не повертати, або 3) розходитися (нескінченна рекурсія). GHC не оптимізує код, припускаючи, що може статися лише 1): якщо f 1
вимагається, він не пропускає свою оцінку та повертається ()
. Семантика Haskell полягає в тому, щоб оцінити її і побачити, що відбувається серед 1,2,3.
()
цьому питанні насправді немає нічого особливого (ні типу, ні значення). Все ті ж спостереження трапляються, якщо замінити () :: ()
їх, скажімо, 0 :: Int
скрізь. Це все просто нудні старі наслідки лінивої оцінки.
()
типу, ()
і undefined
.
h1::()->() ; h1 () = ()
таh2::()->() ; h2 _ = ()
. Запустітьh1 (f 1)
і теh2 (f 1)
, і подивіться, що вимагає лише перший(f 1)
.