Tak jak w tytule: jakie są gwarancje, że jednostka zwrotna funkcji Haskell zostanie poddana ocenie? Można by pomyśleć, że w takim przypadku nie ma potrzeby przeprowadzania żadnej oceny, kompilator mógłby zastąpić wszystkie takie wywołania natychmiastową ()
wartością, chyba że istnieją wyraźne żądania zachowania ścisłości, w którym to przypadku kod może zdecydować, czy powinien powrót ()
lub dół.
Eksperymentowałem z tym w GHCi i wydaje się, że dzieje się odwrotnie, to znaczy, że taka funkcja wydaje się być oceniana. Byłby to bardzo prymitywny przykład
f :: a -> ()
f _ = undefined
Ocena f 1
powoduje błąd z powodu obecności undefined
, więc pewna ocena zdecydowanie się zdarza. Nie jest jednak jasne, jak daleko sięga ocena; czasami wydaje się, że idzie tak głęboko, jak to konieczne, aby ocenić wszystkie powracające wywołania funkcji ()
. Przykład:
g :: [a] -> ()
g [] = ()
g (_:xs) = g xs
Ten kod zapętla się w nieskończoność, jeśli jest wyświetlany z g (let x = 1:x in x)
. Ale wtedy
f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()
może być użyty do pokazania, że h (f 1)
zwraca ()
, więc w tym przypadku nie wszystkie podwyrażenia o wartości jednostkowej są oceniane. Jaka jest tutaj ogólna zasada?
ETA: oczywiście wiem o lenistwie. Pytam, co uniemożliwia pisarzom kompilatorów uczynienie tego konkretnego przypadku jeszcze bardziej leniwym, niż zwykle jest to możliwe.
ETA2: podsumowanie przykładów: GHC wydaje się traktować ()
dokładnie tak, jak każdy inny typ, tzn. Jakby istniało pytanie o to, która regularna wartość zamieszkująca ten typ powinna zostać zwrócona z funkcji. Fakt, że istnieje tylko jedna taka wartość, nie wydaje się (ab) wykorzystywany przez algorytmy optymalizacyjne.
ETA3: kiedy mówię Haskell, mam na myśli Haskella, jak zdefiniowano w Raporcie, a nie Haskell-the-H-in-GHC. Wydaje się, że jest to założenie, które nie jest tak szeroko rozpowszechnione, jak sobie wyobrażałem (co stanowiło „100% czytelników”), lub prawdopodobnie byłbym w stanie sformułować jaśniejsze pytanie. Mimo to żałuję, że zmieniłem tytuł pytania, ponieważ pierwotnie pytano, jakie są gwarancje wywołania takiej funkcji.
ETA4: wydaje się, że pytanie to już się potoczyło i uważam, że nie ma na nie odpowiedzi. (Szukałem funkcji „zamknij pytanie”, ale znalazłem tylko „odpowiedz na swoje pytanie”, a ponieważ nie można na nie odpowiedzieć, nie poszedłem tą drogą.) Nikt nie przywołał niczego w Raporcie, które by to zadecydowało w obu przypadkach , który kusi mnie, by interpretować jako mocną, ale nieokreśloną odpowiedź „nie ma gwarancji dla języka jako takiego”. Wiemy tylko, że obecna implementacja GHC nie pominie oceny takiej funkcji.
Natknąłem się na rzeczywisty problem podczas przenoszenia aplikacji OCaml do Haskell. Oryginalna aplikacja miała wzajemnie rekurencyjną strukturę wielu typów, a kod zadeklarował szereg funkcji wywoływanych assert_structureN_is_correct
dla N w 1..6 lub 7, z których każda zwróciła jednostkę, jeśli struktura była rzeczywiście poprawna, i zgłosiła wyjątek, jeśli nie była . Ponadto funkcje te wywoływały się nawzajem, ponieważ rozkładały warunki poprawności. W Haskell lepiej sobie z tym Either String
poradzić za pomocą monady, więc zapisałem to w ten sposób, ale pytanie jako kwestia teoretyczna pozostało. Dzięki za wszystkie dane wejściowe i odpowiedzi.
f 1
jest „zastąpiony” przez undefined
we wszystkich przypadkach.
... -> ()
może 1) zakończyć i zwrócić ()
, 2) zakończyć z błędem wyjątku / czasu działania i nie zwrócić niczego, lub 3) odejść (nieskończona rekurencja). GHC nie optymalizuje kodu, zakładając, że tylko 1) może się zdarzyć: jeśli f 1
jest wymagany, nie pomija jego oceny i powrotu ()
. Semantyka Haskella polega na jej ocenie i sprawdzeniu, co dzieje się wśród 1,2,3.
()
tym pytaniu nie ma nic specjalnego (ani typu, ani wartości). Wszystkie te same obserwacje zdarzają się, jeśli zastąpisz () :: ()
je, powiedzmy, 0 :: Int
wszędzie. To wszystko nudne stare konsekwencje leniwej oceny.
()
typu ()
i undefined
.
h1::()->() ; h1 () = ()
ih2::()->() ; h2 _ = ()
. Uruchom obah1 (f 1)
ih2 (f 1)
i przekonaj się, że wymaga tego tylko pierwszy(f 1)
.