Jest to sugerowana „interpretacja” IOmonady. Jeśli chcesz poważnie potraktować tę „interpretację”, musisz poważnie potraktować „RealWorld”. Nie ma znaczenia, czy action worldzostanie spekulacyjnie oceniony, czy nie, actionnie ma żadnych skutków ubocznych, jego ewentualne skutki są obsługiwane przez zwrócenie nowego stanu wszechświata, w którym wystąpiły te efekty, np. Wysłano pakiet sieciowy. Jednak wynikiem tej funkcji jest ((),world)nowy stan wszechświata world. Nie używamy nowego wszechświata, który mogliśmy spekulować na boku. Stan wszechświata jest world.
Prawdopodobnie trudno ci brać to na poważnie. Jest na wiele sposobów, w najlepszym wypadku, powierzchownie paradoksalny i bezsensowny. Z tej perspektywy współbieżność jest albo nieoczywista, albo szalona.
„Czekaj, czekaj” - mówisz. „ RealWorldto tylko„ token ”. To nie jest stan całego wszechświata.” Okej, to ta „interpretacja” nic nie wyjaśnia. Niemniej jednak, jako szczegół implementacji , tak właśnie modele GHC IO. 1 Oznacza to jednak, że mamy magiczne „funkcje”, które faktycznie wywołują skutki uboczne i ten model nie zawiera wskazówek co do ich znaczenia. A ponieważ te funkcje faktycznie wywołują skutki uboczne, twoja obawa jest całkowicie na miejscu. GHC nie trzeba wychodzić z jego sposób, aby upewnić się RealWorld, a te specjalne funkcje nie są zoptymalizowane w taki sposób, że zmiany zamierzonego zachowania programu.
Osobiście (jak to zapewne jest obecnie widoczne), uważam, że ten „przemijający świat” model IOjest po prostu bezużyteczny i mylący jako narzędzie pedagogiczne. (Nie wiem, czy jest to przydatne do implementacji. W przypadku GHC uważam, że jest to raczej historyczny artefakt).
Jednym z alternatywnych podejść jest wyświetlanie IOżądań opisujących za pomocą procedur obsługi odpowiedzi. Można to zrobić na kilka sposobów. Prawdopodobnie najbardziej dostępna jest darmowa konstrukcja monady, w szczególności możemy użyć:
data IO a = Return a | Request OSRequest (OSResponse -> IO a)
Istnieje wiele sposobów, aby uczynić to bardziej wyrafinowanym i mieć nieco lepsze właściwości, ale jest to już poprawa. Nie wymaga głębokich filozoficznych założeń dotyczących natury rzeczywistości. Stwierdza tylko, że IOjest to albo trywialny program Return, który nic nie robi, ale zwraca wartość, albo jest to żądanie do systemu operacyjnego z funkcją obsługi odpowiedzi. OSRequestmoże być coś takiego:
data OSRequest = OpenFile FilePath | PutStr String | ...
Podobnie OSResponsemoże być coś takiego:
data OSResponse = Errno Int | OpenSucceeded Handle | ...
(Jednym z ulepszeń, które mogą być wykonane jest, aby rzeczy bardziej wpisz bezpieczny tak, że wiesz, że nie będzie się OpenSucceededz PutStrwniosku). To modele IOjak opisujący wnioski, które uzyskać interpretowane przez jakiegoś układu (za „prawdziwe” IOmonada jest sam środowisko uruchomieniowe Haskell), a następnie być może ten system wywoła moduł obsługi, którego udzieliliśmy odpowiedzi. To oczywiście nie daje żadnych wskazówek na temat tego, jak PutStr "hello world"należy obsługiwać takie żądanie , ale też nie udaje. Wyjaśnia, że jest to delegowane do innego systemu. Ten model jest również dość dokładny. Wszystkie programy użytkownika we współczesnych systemach operacyjnych muszą wysyłać żądania do systemu operacyjnego, aby cokolwiek zrobić.
Ten model zapewnia właściwe intuicje. Na przykład wielu początkujących uważa rzeczy takie jak <-operator za „rozpakowywanie” IOlub mają (niestety wzmocnione) widoki, które IO String, powiedzmy, są „pojemnikami”, które „zawierają” String(a następnie <-wyciągają je). Ten widok żądanie-odpowiedź sprawia, że ta perspektywa jest wyraźnie błędna. Wewnątrz nie ma uchwytu pliku OpenFile "foo" (\r -> ...). Popularną analogią do podkreślenia tego jest to, że w przepisie na ciasto nie ma ciasta (a może w tym przypadku lepiej byłoby „wystawić fakturę”).
Ten model działa również z współbieżnością. Możemy łatwo mieć konstruktor dla OSRequestlike, Fork :: (OSResponse -> IO ()) -> OSRequesta następnie środowisko wykonawcze może przeplatać żądania wygenerowane przez ten dodatkowy moduł obsługi z normalnym modułem obsługi, jak mu się podoba. Przy odrobinie sprytu możesz użyć tej (lub pokrewnych technik) do modelowania rzeczy takich jak współbieżność bardziej bezpośrednio, niż po prostu mówiąc „wysyłamy zapytanie do systemu operacyjnego i rzeczy się dzieją”. Tak działa IOSpecbiblioteka .
1 Uściski zastosowały kontynuację, IOktóra jest mniej więcej podobna do tego, co opisuję, aczkolwiek z nieprzezroczystymi funkcjami zamiast jawnego typu danych. HBC wykorzystał również implementację opartą na kontynuacji warstwową na starym IO opartym na strumieniu żądanie-odpowiedź. NHC (a tym samym YHC) użył thunksów, tzn. Z grubsza, IO a = () -> ajak ()to się nazywało World, ale nie robi stanu. JHC i UHC zastosowały w zasadzie to samo podejście co GHC.