Использование отладчика 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.

Другие вопросы по тегам