19
votes

Char is the type for Unicode characters in Haskell, and String is simply [Char] (i.e. a list of Char items). Here is some simple code:

main = putStrLn "©" -- Unicode string

This code compiles fine, but I get the runtime exception when I run it in the PowerShel.exe or cmd.exe:

app.exe: : commitBuffer: invalid argument (invalid character)

Why does this happen? Weirdly enough, when I do the same in C#, I get no exception:

Console.WriteLine("©");

In .NET, chars are Unicode too. PowerShell or cmd prints c instead ©, but at least I get not exception. How can I get my Haskell executable to run smoothly?

2
Might be that Haskell requires that program to be ran in the unicode shell.Bartek Banachewicz
My cmd shell prints "©" fine but chokes with the same error on "ഠഃ അ ഠൃ ൩".chi
Possibly useful: stackoverflow.com/questions/22349139/… I'm no PowerShell or C# expert, but the fact that some character substitution occurs ("c" instead of "©") when you run your C# program may indicate that PowerShell isn't set to use UTF-8... @chi That Unicode string prints out fine on Mac OS X; I use bash via Terminal, which is set to use UTF-8.jub0bs
@Jubobs Indeed, on linux the terminal is set to UTF-8 as well, and I never had issues there. @Bush If all you want is avoid exceptions, you can use chcp 65001 in the terminal -- all non ascii characters will be unreadable, though.chi
@Bush Have you set your code page using chcp.com 65001?bheklilr

2 Answers

5
votes

I think this should count as a bug in GHC, but there is a workaround. The default encoding for all handles in a GHC program (except those opened in Binary mode) is just the encoding accepted by the console with no error handling. Fortunately you can add error handling with something like this.

makeSafe h = do
  ce' <- hGetEncoding h
  case ce' of
    Nothing -> return ()
    Just ce -> mkTextEncoding ((takeWhile (/= '/') $ show ce) ++ "//TRANSLIT") >>=
      hSetEncoding h

main = do
  mapM_ makeSafe [stdout, stdin, stderr]
  -- The rest of your main function.
9
votes

On Windows, the fix is to tell the shell to use code page 65001 (instructions here), which puts Windows in "UTF-8 mode". It's not perfect, but for most characters you should see unicode characters handled much better.