Главный ответ отличный. Вот что я должен был на обычной установке debian / php / mysql:
// storage
// debian. apparently already utf-8
// retrieval
// the mysql database was stored in utf-8,
// but apparently php was requesting iso. this worked:
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');
// delivery
// php.ini did not have a default charset,
// (it was commented out, shared host) and
// no http encoding was specified in the apache headers.
// this made apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');
// submission
// this worked in all major browsers once apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.
// processing
// changed a few commands in php, like substr,
// to mb_substr
, которая была всем!
До введения монады IO main
была функцией типа [Response] -> [Request]
. A Request
будет представлять собой действие ввода-вывода, например, запись в канал или файл, чтение ввода или чтение переменных среды и т. Д. А Response
будет результатом такого действия. Например, если вы выполнили запрос ReadChan
или ReadFile
, соответствующий Response
будет Str str
, где str
будет String
, содержащим вход для чтения. При выполнении запроса AppendChan
, AppendFile
или WriteFile
ответ будет просто Success
. (Предполагая, во всех случаях, что данное действие было действительно успешным, конечно).
Таким образом, программа Haskell будет работать, создавая список значений Request
и считывая соответствующие ответы из списка main
. Например, программа для чтения числа от пользователя может выглядеть так (без всякой необходимости обращаться к ошибкам):
main :: [Response] -> [Request]
main responses =
[
AppendChan "stdout" "Please enter a Number\n",
ReadChan "stdin",
AppendChan "stdout" . show $ enteredNumber * 2
]
where (Str input) = responses !! 1
firstLine = head . lines $ input
enteredNumber = read firstLine
Как уже указывал в комментарии Стивен Тетли, детальная спецификация эта модель приведена в главе 7 1.2 Haskell Report .
Могут ли I / O выполняться без IO Monad в современном Haskell?
blockquote>Нет. Haskell больше не поддерживает способ
Response
/Request
делать IO напрямую, а типmain
теперьIO ()
, поэтому вы не можете писать программу Haskell, которая не включаетIO
и даже если вы могли бы, у вас все равно не было бы альтернативного способа ввода / вывода.Однако вы можете написать функцию, которая принимает основную функцию старого стиля и превращает ее в IO. Затем вы могли бы написать все, используя старый стиль, а затем использовать только IO в
main
, где вы просто вызываете функцию преобразования на вашей реальной основной функции. Это почти наверняка будет более громоздким, чем использование монадыIO
(и будет путать ад из любого современного Haskeller, читающего ваш код), поэтому я определенно не рекомендовал бы его. Однако является возможным. Такая функция преобразования может выглядеть так:import System.IO.Unsafe -- Since the Request and Response types no longer exist, we have to redefine -- them here ourselves. To support more I/O operations, we'd need to expand -- these types data Request = ReadChan String | AppendChan String String data Response = Success | Str String deriving Show -- Execute a request using the IO monad and return the corresponding Response. executeRequest :: Request -> IO Response executeRequest (AppendChan "stdout" message) = do putStr message return Success executeRequest (AppendChan chan _) = error ("Output channel " ++ chan ++ " not supported") executeRequest (ReadChan "stdin") = do input <- getContents return $ Str input executeRequest (ReadChan chan) = error ("Input channel " ++ chan ++ " not supported") -- Take an old style main function and turn it into an IO action executeOldStyleMain :: ([Response] -> [Request]) -> IO () executeOldStyleMain oldStyleMain = do -- I'm really sorry for this. -- I don't think it is possible to write this function without unsafePerformIO let responses = map (unsafePerformIO . executeRequest) . oldStyleMain $ responses -- Make sure that all responses are evaluated (so that the I/O actually takes -- place) and then return () foldr seq (return ()) responses
Затем вы можете использовать эту функцию следующим образом:
-- In an old-style Haskell application to double a number, this would be the -- main function doubleUserInput :: [Response] -> [Request] doubleUserInput responses = [ AppendChan "stdout" "Please enter a Number\n", ReadChan "stdin", AppendChan "stdout" . show $ enteredNumber * 2 ] where (Str input) = responses !! 1 firstLine = head . lines $ input enteredNumber = read firstLine main :: IO () main = executeOldStyleMain doubleUserInput
@ sepp2k уже разъяснил, как это работает, но я хотел добавить несколько слов, аким, несколько строк кода.
Мне очень жаль это. Я не думаю, что эту функцию можно написать без unsafePerformIO
blockquote>Конечно, вы можете! Вы почти никогда не должны использовать unsafePerformIO http://chrisdone.com/posts/haskellers
Я использую немного другой конструктор типа
Request
, так что он не принимает канал версия (stdin
/stdout
, как в коде @ sepp2k). Вот мое решение для этого:(Примечание:
getFirstReq
не работает в пустом списке, вам нужно будет добавить к нему случай, bu должно быть тривиально)data Request = Readline | PutStrLn String data Response = Success | Str String type Dialog = [Response] -> [Request] execRequest :: Request -> IO Response execRequest Readline = getLine >>= \s -> return (Str s) execRequest (PutStrLn s) = putStrLn s >> return Success dialogToIOMonad :: Dialog -> IO () dialogToIOMonad dialog = let getFirstReq :: Dialog -> Request getFirstReq dialog = let (req:_) = dialog [] in req getTailReqs :: Dialog -> Response -> Dialog getTailReqs dialog resp = \resps -> let (_:reqs) = dialog (resp:resps) in reqs in do let req = getFirstReq dialog resp <- execRequest req dialogToIOMonad (getTailReqs dialog resp)