Использование отладчика Leksah с программами, использующими readLn и аналогичные
Я недавно установил Leksah (0.10.0.4 в 64-битной Windows 7), который кажется интересной IDE для Haskell. Тем не менее, я явно что-то упускаю из виду, когда дело доходит до ввода пользователем программ при его использовании.
У меня очень просто
do
printStr "Prompt: "
x <- readLn
блок в моем коде. Когда отладчик нажимает на readLn, я ожидаю, что смогу где-то предоставить ввод. Тем не менее, я не могу найти ни одного окна ввода. Сначала я ожидал, что окно журнала может быть включено, но я не могу найти где-нибудь взаимодействовать с программой. В GHCi все работает так, как ожидалось, поэтому я уверен, что это не код.
Кроме того, когда я просто делаю "Package->Run", приглашение не становится видимым, пока не поступит какой-либо другой вывод журнала (например, перестроение).
В прошлом, когда я использовал Emacs с режимом Haskell для Linux, я надеялся на более удобный для пользователя интерфейс, чтобы я мог привлекать некоторых программистов Windows по темам Haskell. Я что-то пропустил?
3 ответа
Из этой темы http://groups.google.com/group/leksah/browse_thread/thread/7d3e3bf64e56f190/30278795c23b2168
Это известная проблема, которую мы еще не рассмотрели. Мы посылаем команды GCHi на его стандартный ввод, но у нас нет и хорошего способа отправить туда пользовательский ввод.
Я не уверен, как мы должны это исправить. Мы не можем отправить пользовательский ввод в процесс, который отлаживается с помощью нашего командного канала (наш код ждет приглашения от ghci перед отправкой команд).
Если мы настроим какой-либо способ отправки данных в stdin без ожидания, это может помешать командам GHCi, которые мы отправляем (потому что они все еще идут по одному и тому же каналу).
Нам нужно выяснить, есть ли какой-нибудь способ, которым мы можем иметь отдельные каналы stdin/stdout/stderr для самого GHCi, и программа GHCi отлаживается.
В то же время вы можете сделать так, чтобы ваше приложение открывало сокет или именованный канал и записывало входные данные с другого терминала. Как то так (не проверено)...
main = do
sock <- listenOn (PortNumber 8000)
-- Start a new terminal window (this command needs to be changed for OS X or Windows)
forkIO $ system "gnome-terminal -e \"telnet localhost 8000\""
(handle, _, _) <- accept sock -- Wait for the new terminal to connect
-- You might want to add a call to hSetBuffering here
line <- hGetLine handle
print line
sClose sock
(Вам нужно будет добавить процесс и сеть в зависимости вашего пакета. Затем Ctrl+R должен добавить необходимые операторы импорта.)
Это позволит взаимодействовать, но держите лекды в чистоте, чтобы лексы могли разговаривать с ghci. В идеале вы должны держать stdout и stderr в чистоте и вместо этого писать в этот сокет, но Leksah должен довольно хорошо справляться с произвольным выводом.
Я столкнулся с той же проблемой, и я рассматриваю возможность использования препроцессора C, чтобы буквально определить, хочу ли я вводить ложные данные для тестирования или нет. Что-то вроде этого:
{-# LANGUAGE CPP, TemplateHaskell #-}
module Main (
main
) where
#define FAKE_INPUT
main :: IO ()
main = do
putStrLn "Prompt: "
x <- myReadLn
putStrLn x
#ifdef FAKE_INPUT
myReadLn = return "fake string"
#else
myReadLn = readLn
#endif
Вы можете закомментировать строку, которая #defines FAKE_INPUT, когда вы хотите проверить с реальными функциями (за пределами Leksah). Вы также можете получить фантазию и иметь несколько констант для нескольких входов, но это начинается с модульного тестирования, которое может оказаться лучшим решением в конце.
Я не использую Leksah, поэтому я не могу ответить на эту часть вашего вопроса, однако ваша проблема при использовании Package -> Run
вызвано тем, что приглашение хранится в буфере, а не выводится немедленно.
Режим буферизации вывода по умолчанию определяется реализацией, но для терминалов обычно это буферизация строки, что означает, что буфер сбрасывается в выходной поток всякий раз, когда вы добавляете в него новую строку, тогда как в GHCi буферизация обычно отключена.
Поскольку после запроса на запуск сброса в режиме буферизации строки нет новой строки, вам необходимо hFlush stdout
себя или hSetBuffering stdout NoBuffering
отключить буферизацию вообще.
Для получения дополнительной информации см. Операции буферизации System.IO.