С Clean 2.2 manual, глава 9:
Although Clean is purely functional, operations with side-effects (I/O operations, for instance) are permitted. To achieve this without violating the semantics, the classical types are supplied with so called uniqueness attributes. If an argument of a function is indicated as unique, it is guaranteed that at run-time the corresponding actual object is local, i.e. there are no other references to it. Clearly, a destructive update of such a “unique object” can be performed safely.
В частности, вы можете сделать Start
, который обычно имеет Арность 0 (не принимает никаких аргументов), функцию от *World
к *World
. Идея состоит в том, что теперь у нас есть функция, которая меняет мир, а это означает, что допустимы побочные эффекты (они больше не являются побочными эффектами, а являются операциями в мире).
*
указывает уникальностьWorld
. Это означает, что вы никогда не можете иметь два экземпляра мирового аргумента. Например, следующий будет дать время компиляции уникальность ошибки:
Start :: *World -> *(*World, *World)
Start w = (w, w)
Для использования стандартного ввода-вывода, вам необходимы функции из модуля StdFile
в StdEnv
. Функции, которые вы собираетесь нужны:
stdio :: !*World -> *(!*File, !*World)
fclose :: !*File !*World -> !(!Bool, !*World)
Я упрощена типам немного, на самом деле они из класса FileSystem
. stdio
открывает уникальныйFile
из мира, а также возвращает новый, измененный мир. fclose
закрывает файл в мире и возвращает флаг успеха и измененный мир.
Затем, чтобы читать и писать из этого STDIO файла, вы можете использовать:
freadline :: !*File -> *(!*String, !*File)
fwrites :: !String !*File -> !*File
freadline
читает строку в строку, включая символ новой строки. fwrites
записывает строку в файл, обычно вы хотите включить символ новой строки при записи в stdio.
Собираем вместе:
Start :: *World -> *World
Start w
# (io,w) = stdio w // open stdio
# io = fwrites "What is your name?\n" io // ask for name
# (name,io) = freadline io // read in name
# name = name % (0, size name - 2) // remove \n from name
# io = fwrites ("Hello, " +++ name +++ "!\n") io // greet user
# (ok,w) = fclose io w // close stdio
| not ok = abort "Couldn't close stdio" // abort in case of failure
= w // return world from Start
Синтаксис #
может быть новым для вас. Это своего рода let
, который позволяет использовать такое же имя для файлов (или других вещей), что более удобно, чем при использовании, например:
Start w = w3
where
(io, w1) = stdio w
io1 = fwrites "What is your name?\n" io
(name, io2) = freadline io1
//...
(ok, w3) = fclose io10 w2
Теперь вы должны быть в состоянии делать то, что вы хотите в псевдокоде, используя вспомогательная функция loop :: *File -> *File
, которая называет себя рекурсивно до ввода q
.
Есть больше функций, чем только freadline
и fwrites
, см. StdFile.dcl
за идею.
Почему вы не используете Google, чтобы найти учебник и сделать это самостоятельно? –
Я не могу этого найти. вы можете дать мне ссылку? Пожалуйста. Благодарю. –
[one google search away] (http://www.inf.ufsc.br/~jbosco/cleanBookI.pdf) –