#functional-programming #clean-language
#функциональное программирование #чистый язык
Вопрос:
Я пытаюсь написать функцию, которая получает, [String]
которые являются именами файлов, String
которые являются именем каталога файлов и *f
. Функция добавит к каждому файлу целое число в конце.
Вот что у меня получилось на данный момент:
import StdEnv
import StdFile
import FileManipulation
appendNumInEndOfVmFiles :: [String] String *f -> String
appendNumInEndOfVmFiles [] dirname w = "finished"
appendNumInEndOfVmFiles [x:xs] dirname w
# path = dirname "\\" x
# (ok,file,files) = fopen path FAppendText w
# file = fwritei 12 file
# (ok2,_) = fclose file w
= appendNumInEndOfVmFiles xs dirname w
Start w
// 1. Receive name of directory from the user.
# (io,w) = stdio w // open stdio
# io = fwrites "Enter name of directory:n" io // ask for name
# (name,io) = freadline io // read in name
# name = name % (0, size name - 2) // remove n from name
# (ok,w) = fclose io w // close stdio
| not ok = abort "Couldn't close stdio" // abort in case of failure
// 2. Get a list of all file names in that directory.
# (dir,w) = getDirectoryContents (RelativePath [PathDown name]) w
# fileList = getNamesOfFilesInDirectory (getEntriesList dir)
= appendNumInEndOfVmFiles (getVmFiles fileList) name w
Предположим, что getVmFiles
определено в моем FileManipulation.dcl
файле и в контексте этой проблемы name
является "myDir"
, а список файлов является ["hello.vm","Wiki.vm"]
По какой-то причине, даже когда я получил сообщение «готово» на экране, файлы не были изменены. Независимо от того, какое целое число я даю fopen
, даже если его FWriteText
или FWriteData
оно по-прежнему ничего не делает… кроме того, даже если я использую fwritec
или fwrites
с символами, ничего не произошло.
Чего мне здесь не хватает? Большое спасибо!
Ответ №1:
По какой-то причине, даже когда я получил сообщение «готово» на экране, файлы не были изменены.
Это связано с отложенной оценкой. В appendNumInEndOfVmFiles
результат fclose
не используется, поэтому fclose
не оценивается. Из-за этого fwritei
также не нужно оценивать. Вы можете исправить это, добавив защиту на ok2
:
# (ok2,_) = fclose file w
| not ok2 = abort "fclose failedn"
= appendNumInEndOfVmFiles xs dirname w
Однако типичным способом сделать это было бы переписать функцию, чтобы возвращать *f
вместо String
a, чтобы это уникальное значение не было потеряно. Пока используется результат, то fwritei
вычисляется. Потенциально можно сделать *f
аргумент строгим (т.Е. добавить !
перед ним). Это позволило бы убедиться, что он вычисляется перед входом в функцию, так что все длительные закрытия файлов были выполнены.
Есть еще несколько проблем с вашим кодом:
-
Здесь
w
используется дважды, что незаконно, поскольку оно имеет строгий тип. Вы должны использовать(ok2,w)
в guard для продолжения работы с той же средой.# (ok2,_) = fclose file w = appendNumInEndOfVmFiles xs dirname w
-
appendNumInEndOfVmFiles
Должен иметь контекст типа| FileSystem f
, чтобы разрешить перегрузкуfopen
иfclose
.
Наконец:
… даже если это
FWriteText
илиFWriteData
…
Просто чтобы вы знали: разница будет заключаться в том, что первый запишет целое число в представлении ASCII, тогда как второй запишет его в двоичном виде в виде 4 или 8 байт (в зависимости от разрядности вашей системы).
Комментарии:
1. Спасибо. Я исправил свой код и его работоспособность. можете ли вы подробнее объяснить об этом,
| FileSystem f
что там на самом деле происходит? также почему я должен использовать(ok2,w)
в guard? Я думал,_
этого достаточно.2. @ZENir извините, ваш комментарий затерялся в моем почтовом ящике.
| FileSystem f
это контекст класса, вы можете прочитать больше об этом в разделе 6 отчета о языке. Короче говоря, он содержит необходимые функцииfopen
иfclose
, которые могут иметь разные реализации в зависимости отf
. Защита заключается в принудительной оценкеfclose
. Это несколько похоже на то, что происходит в C-подобном языке, когда вы пишете(true || f(x))
:f(x)
не выполняется, потому что это не требуется для оценки||
. Вы знакомы с отложенным вычислением?