Что, если таковые имеются, с этим подходом к декларативному вводу-выводу - PullRequest
2 голосов
/ 04 июня 2010

Я не уверен, насколько точно это относится к «программированию», а не к «проектированию языка программирования». Но проблема в следующем:

Скажем, ради простоты у нас есть два «специальных» списка / массива / вектора / что бы мы просто не называли «портами» для простоты, один называется stdIn, а другой stdOut. Они концептуально представляют соответственно

  • Все пользовательские данные, введенные программе в течение действия программы
  • Весь вывод записывается на терминал за время работы программы

В псевдокоде, вдохновленном Haskell, должна быть возможность создать эту полностью декларативную программу:

 let stdOut =   ["please input a number", 
                "and please input another number", 
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

Что бы сделать ожидаемое, попросить два числа и распечатать их продукт. Хитрость заключается в том, что stdOut представляет список строк, записанных в терминал при завершении программы, и stdIn в списке входных строк. Ошибки типа и тот факт, что должна быть какая-то мера предосторожности для печати следующей строки только после ввода новой строки, оставленной здесь для простоты, вероятно, это достаточно легко решить.

Итак, прежде чем я приступлю к реализации этой идеи, есть ли какие-то подводные камни, которые я упустил из виду? Я не знаю о подобной конструкции, уже существующей, поэтому было бы наивно не принимать во внимание очевидную ловушку, которую я упустил из виду.

В противном случае, я знаю это, конечно:

 let stdOut =   [stdIn[50],"Hello, World!"]

Было бы ошибкой, если эти результаты должны быть переплетены таким же образом, как указано выше.

Ответы [ 4 ]

6 голосов
/ 04 июня 2010

Аналогичный подход использовался в ранних версиях Haskell, за исключением того, что элементы каналов stdin и stdout были не строками, а общими «действиями» ввода-вывода - фактически ввод и вывод были обобщены на «response» и «request». ». Пока оба канала являются ленивыми (то есть они фактически являются «итераторами» или «перечислителями»), среда выполнения может просто обходить канал запроса, воздействовать на каждый запрос и направлять соответствующие ответы в канал ответа. К сожалению, система была очень сложной в использовании, поэтому она была отменена в пользу монадического ввода-вывода. Смотрите эти документы:

  • Гудак П., Сундареш Р. О выразительности чисто функциональных систем ввода / вывода. Tech. Rep. YALEU / DCS / RR-665, факультет компьютерных наук, Йельский университет, март 1989 г.
  • Пейтон Джонс, С. Борьба с неуклюжим отрядом: монадический ввод / вывод, параллелизм, исключения и вызовы на иностранных языках в Haskell. Инженерные теории построения программного обеспечения, 2002, с. 47--96.
5 голосов
/ 04 июня 2010

Подход, который вы описываете, звучит как «Диалоги». В своей отмеченной наградами работе 1993 года Императивное функциональное программирование Фил Уодлер и Саймон Пейтон Джонс приводят несколько примеров, когда диалоги действительно не очень хорошо работают, и объясняют, почему монадический ввод / вывод лучше.

1 голос
/ 04 июня 2010

Этот подход кажется «наиболее очевидным» способом добавления ввода / вывода к чистому λ-исчислению, и другие люди упоминали, что что-то в этом роде было опробовано в Haskell и Miranda.

Однако мне известен язык, не основанный на λ-исчислении, в котором все еще используется очень похожая система:

Как обрабатывать ввод и вывод в язык без побочных эффектов? В определенный смысл, вход и выход не побочные эффекты; они, так сказать, фронтальные и обратные эффекты. (...) [Программа есть] функция из космоса возможных входов в пространство возможные выходы.

Входные и выходные потоки представлены в виде списков природных числа от 0 до 255, каждый соответствует одному байту. Заключительная файла представлен значением 256, а не к концу списка. (Это потому что часто легче иметь дело с EOF как характер, чем в особом случае. Тем не менее, мне интересно, если бы не лучше использовать конец списка.)

(...)

Не сложно написать интерактивные программы (...) [но] делают технически говоря, это грех. (...) в ссылочно прозрачной язык, ничего не явно синхронизирована это честная игра для оценка в любом порядке, на усмотрение системы времени выполнения.

(...) Самый очевидный способ написания эта конкретная программа имеет минусы вместе "Привет, [имя]!" строка в выражении, которое обусловлено при получении новой строки. Если вы делаете это вы в безопасности, потому что нет способ для любого оценщика, чтобы доказать в заранее, что пользователь будет когда-либо печатать символ новой строки.

(...)

Так что с практической проблемой нет интерактивное программное обеспечение. тем не менее, есть что-то неприятное в Кстати, второй случай предотвращен. референтно прозрачная программа не должен полагаться на ленивых оценка для правильной работы.

Как избежать этой моральной дилеммы? трудный путь состоит в том, чтобы перейти к более сложная система ввода / вывода, возможно на основе Хаскелла, в котором вход и выходные данные явно синхронизированы. Я довольно не склонен делать это, так как Я предпочитаю простоту текущая система. Самый простой выход написать пакетные программы, которые происходят с хорошо работать в интерактивном режиме. Это в основном просто вопрос не подсказывать пользователь.

Возможно, вам понравится заниматься программированием в Lazy K ?

1 голос
/ 04 июня 2010

Я не понимаю, как вы будете плести их с учетом этого примера по сравнению с вашим собственным:

let stdOut =   ["Welcome to the program which multiplies.",
                "please input a number", 
                "and please input another number", 
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

Должна ли программа запрашивать число, представленное stdIn[0], после вывода одной строки (как в вашем примере) или двух строк? Если индекс 0 представляет 0-й вход из stdin, то он выглядит примерно так:

let stdOut =   ["Welcome to the program which multiplies.",
                "please input a number",
                some_annotation(stdIn[0]),
                "and please input another number", 
                some_annotation(stdIn[1]),
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

потребуется для согласования времени вывода и ввода.

Мне нравится твоя идея. Замените some_annotation вашими предпочтениями, возможно, что-то вроде "синхронизировать?" Я не мог придумать острое слово для этого.

...