I / O konsoli Unicode w Haskell w systemie Windows

Wydaje się, że trudno uzyskać konsolę I / O do pracy ze znakami Unicode w Haskell pod Windows. Oto opowieść o biada:

(Preliminary.) Zanim w ogóle rozważysz wykonanie Unicode I / O w konsoli pod Windows, musisz upewnić się, że używasz czcionki konsoli, która może renderować znaki, które chcesz. Czcionki rastrowe (domyślne) mają nieskończenie słabe pokrycie (i nie pozwalają na wklejanie kopii znaków, których nie mogą reprezentować), a opcje truetype, które zapewnia MS (consolas, konsola lucida), nie mają dużego zasięgu (chociaż te pozwolą kopiowanie / wklejanie znaków, których nie mogą reprezentować). Możesz rozważyć zainstalowanie DejaVu Sans Mono (postępuj zgodnie z instrukcjami na doletutaj; może być konieczne ponowne uruchomienie, zanim zacznie działać). Dopóki nie zostanie to posortowane, żadne aplikacje nie będą w stanie wykonać dużo operacji we / wy Unicode; nie tylko Haskell.Po wykonaniu tej czynności zauważysz, że niektóre aplikacje będą mogły wykonywać wejścia / wyjścia konsoli pod oknami. Ale doprowadzenie go do działania pozostaje dość skomplikowane. Istnieją zasadniczo dwa sposoby zapisu do konsoli w systemie Windows. (To, co następuje, dotyczy każdego języka, nie tylko Haskell; nie martw się, Haskell wkroczy do obrazu za chwilę!) ...Opcja A polega na użyciu zwykłych funkcji we / wy opartych na bajtach w bibliotece C; nadzieja polega na tym, że system operacyjny zinterpretuje te bajty zgodnie z kodowaniem, które może kodować wszystkie dziwne i wspaniałe znaki, które chcesz. Na przykład, używając równoważnej techniki w systemie Mac OS X, gdzie standardowe kodowanie systemu jest zwykle UTF8, działa to doskonale; wysyłasz wyjście utf8, widzisz ładne symbole.W systemie Windows działa gorzej. Domyślne kodowanie, którego oczekuje system Windows, zazwyczaj nie będzie kodowaniem obejmującym wszystkie symbole Unicode. Więc jeśli chcesz zobaczyć ładne symbole w ten czy inny sposób, musiszzmiana kodowanie. Jedną z możliwości byłoby, aby twój program używałSetConsoleCP polecenie win32. (Więc musisz powiązać się z biblioteką Win32.) Lub, jeśli wolisz tego nie robić, możesz oczekiwać, że użytkownik programu zmieni stronę kodową dla Ciebie (musieliby wtedy zadzwonić dochcp polecenie przed uruchomieniem programu).Opcja B polega na użyciu poleceń API konsoli Win32 obsługujących UnicodeWriteConsoleW. Tutaj wysyłasz UTF16 bezpośrednio do okien, co czyni go szczęśliwym: nie ma niebezpieczeństwa niezgodności kodowania, ponieważ oknazawsze oczekuje UTF16 z tymi funkcjami.

Niestety, żadna z tych opcji nie działa dobrze od Haskella. Po pierwsze, nie ma bibliotek, o których wiem, że używają opcji B, więc nie jest to łatwe. Pozostawia to opcję A. Jeśli korzystasz z biblioteki I / O Haskella (putStrLn i tak dalej, tak zrobi biblioteka. We współczesnych wersjach Haskella będzie starannie pytać okna o to, jaka jest bieżąca strona kodowa, i wypisuje ciągi znaków w odpowiednim kodowaniu. Istnieją dwa problemy z tym podejściem:

Jeden nie jest spektakularny, ale denerwujący. Jak wspomniano powyżej, domyślne kodowanie prawie nigdy nie koduje żądanych znaków: użytkownik musi zmienić kodowanie. W ten sposób użytkownik musichcp cp65001 przed uruchomieniem programu (może okazać się niesmaczne, aby zmusić użytkowników do tego). Lub musisz się związaćSetConsoleCP i wykonaj odpowiednik w programie (a następnie użyjhSetEncoding tak, że biblioteki Haskell będą wysyłać dane wyjściowe przy użyciu nowego kodowania), co oznacza, że ​​należy owinąć odpowiednią część bibliotek win32, aby były widoczne jako Haskell.O wiele poważniej, istniejebłąd w oknach (rozdzielczość: nie naprawi), co prowadzi dobłąd w Haskell co oznacza, że ​​jeśli wybrałeś dowolną stronę kodową, taką jak cp65001, która może obejmować cały Unicode, procedury I / O Haskella będą działać niepoprawnie. Więc zasadniczonawet jeśli Ty (lub Twój użytkownik) ustawiłeś kodowanie na pewne kodowanie, które obejmuje wszystkie cudowne znaki Unicode, a następnie „rób wszystko dobrze”, mówiąc Haskellowi, aby wyprowadzał rzeczy za pomocą tego kodowania, nadal przegrywasz.

Błąd opisany powyżej jest nadal nierozwiązany i wymieniony jako niski priorytet; podstawowy wniosek jest taki, że opcja A (w mojej klasyfikacji powyżej) jest niewykonalna i należy przejść do opcji B, aby uzyskać wiarygodne wyniki. Nie jest jasne, jakie będą ramy czasowe na rozwiązanie tego problemu, ponieważ wygląda to na znaczną pracę.

Pytanie brzmi:w międzyczasie, czy ktoś może zasugerować obejście pozwalające na użycie We / Wy konsoli Unicode w Haskell pod Windows.

Zobacz także towpis bazy danych śledzenia błędów Pythona, borykając się z tym samym problemem w Pythonie 3 (proponowana poprawka, ale jeszcze nie przyjęta do bazy kodu) ita odpowiedź typu stackoverflow, podając obejście tego problemu w Pythonie (na podstawie „opcji B” w mojej klasyfikacji).

questionAnswers(1)

yourAnswerToTheQuestion