Отступ: Вы можете сделать код немного более читабельным, добавив отступ.
fun writeFile (os, args, a) =
if a = -1 then
TextIO.output(os, "rodr4719")
TextIO.closeOut os
OS.Process.exit(OS.Process.success)
else
val str = nth (args, a);
TextIO.output(os, str ^"\n" );
a = a-1;
writeFile(os, args, a)
end
(Этот код все еще не работает по нескольким причинам, перечисленным ниже.)
end
: Это ключевое слово не обязательно, когда вы просто объявляете fun
. Это происходит в нескольких местах в синтаксисе SML, в частности как let ... in ... end
, и вы, вероятно, видели его там.
Имена переменных: Я бы назвал входные аргументы по-другому: os
звучит как операционная система , когда это, вероятно, аббревиатура для outtream . Просто назовите это outstream
. Некоторые люди любят называть это fd
для дескриптор файла , но это все о понимании предполагаемой аудитории. args
может быть более общим: эта функция может записывать любой список строк, а не только аргументы командной строки. Просто назовите это lines
. a
звучит так, как будто это может быть любой тип, но это просто целое число. Я бы назвал это n
, но на самом деле я бы не использовал число для определения моего состояния остановки.
Точки с запятой: Когда ваша функция выполняет несколько действий с побочными эффектами, вы можете использовать оператор ;
. Вы не делаете это в части затем , и вы делаете это неправильно в части else , по общему признанию, потому что оператор ;
в SML - синтаксически сбивает с толку .
Краткая версия: точки с запятой в val foo = x; val bar = y;
отличаются от точек с запятой в val foo = (TextIO.output (fd, x); TextIO.output (fd, y))
.
Если вам нужен оператор точки с запятой expression , поместите выражение с точкой с запятой в круглые скобки или выражение let. В противном случае он интерпретируется как (необязательный) оператор точки с запятой объявление .
При переборе списка строк вместо сохранения счетчика выполняйте сопоставление с образцом в списке. Это значительно упрощает, когда ваша рекурсия заканчивается, так как вы всегда в любом случае обращаетесь к главе списка по очереди.
Не выходите: Вы, вероятно, не хотите выходить из программы, когда закончите; выхода из функции должно быть достаточно. Таким образом, вы можете повторно использовать функцию в более сложном потоке управления, не выходя из нее от имени всей программы.
Открывайте и закрывайте файлы в одной области: Это общий совет по программированию: когда вы имеете дело с побочными эффектами, убедитесь, что вы не забыли закрыть то, что вы ' Если вы открываете что-то и не закрываете что-то дважды, выполнение этого в одной и той же области кода значительно упрощает рассуждения о правильности. Вы можете сделать простой функцией, которая всегда имеет дело с открытием и закрытием .
val
внутри тела функции: Если вам нужно временное связывание значения внутри тела функции или какого-либо выражения, используйте выражение let
. Кстати, кто-то просто спросил Почему я использую `let`, а не просто` val` для объявления переменной внутри функции в SML? сегодня.
Неизменяемые значения : В SML вы не можете обновить значение, подобное a = a-1
. a
не переменная, а привязка значения . Вы можете повторно связать его с новым значением, основанным на старом, таким образом, затеняя старое, но в этом нет необходимости. Вместо этого выполните рекурсивный вызов с обновленным значением.