(ошибка) Вы забыли о let ... in ... end
.
(ошибка) Ваш второй шаблон, []
, никогда не будет соответствовать, потому что первый, x
, является более общим и соответствует всем входным списки (в том числе пустую). Поэтому, даже если ваша синтаксическая ошибка была исправлена, эта функция будет зацикливаться до тех пор, пока она не сработает, потому что вы пытаетесь принять hd
/tl
пустого списка.
(ошибка) Если функция имеет несколько случаев матча, только первый из них должен быть префиксом fun
, а остальные должны быть |
вместо этого. (Вы можете свободно решать, как отступ это.)
(Error) Есть два вида запятой в SML: Один для разделения деклараций, и один оператор, который отбрасывает значение (но не эффект) его первого операнда. Первый вид, который разделяет объявления, всегда можно избежать. Второй вид - это тот, который вы пытаетесь использовать для объединения нескольких выражений, каждый из которых имеет желаемый (файловый ввод-вывод) эффект (и эквивалентен наличию let-выражений с несколькими эффективными объявлениями в строке, как указано выше) ,
Но ... на верхнем уровне (например, в теле функции) SML не может определить разницу между двумя типами точек с запятой, так как они оба могут встречаться там. В конце концов, первый вид, который мы хотим избежать, обозначает окончание тела функции, а второй вид просто отмечает конец подвыражения в теле функции.
Способ избежать этой двусмысленности заключается в том, чтобы обернуть оператор ;
, где объявления не допускаются, например. между in
и end
, или внутри скобки.
(Ошибка) Нет смысла возвращать эту функцию null
. Вероятно, вы думали nil
(пустой список, ака []
), но val null : 'a list -> bool
- это функция!Действительно, бессмысленно иметь возвращаемое значение для этой функции. Во всяком случае, это может быть bool, указывающий, были ли строки написаны успешно (в этом случае вам, вероятно, придется обрабатывать исключения IO). Самое близкое к функции, которая ничего не возвращает, - это функция, которая возвращает тип единица (со значением ()
).
(Предложение) Вы можете использовать hd
/tl
разделить список, но вы также можете использовать поиск по шаблону. Используйте сопоставление шаблонов, как и примеры, которые я дал.
(Предложение) Вы можете использовать полуколоны вместо объявлений val _ = ...
; также; это просто вопрос вкуса. Например .:
fun writeListToFile (s::ss) =
let val fd = TextIO.openAppend filePath
in TextIO.output (fd, s^"\n")
; TextIO.closeOut fd
; writeListToFile ss
end
| writeListToFile [] =()
(Предложение) Это довольно глупо, что каждый раз, когда функция вызывает саму себя, она открывает файл, присоединяет и закрывает файл. В идеале вы только открыть и закрыть файл один раз:
fun writeListToFile lines =
let val fd = TextIO.openAppend filePath
fun go [] = TextIO.closeOut fd
| go (s::ss) = (TextIO.output (fd, s^"\n") ; go ss)
in go lines end
(Предложение) Поскольку вы делаете то же самое для каждого элемента в списке, вы можете также рассмотреть возможность использования функции высшего порядка, обобщающую итерация. Как правило, это было бы val map : ('a -> 'b) -> 'a list -> 'b list
, но так как TextIO.output
она возвращает блок, очень похоже val app : ('a -> unit) -> 'a list -> unit
еще лучше:
fun writeListToFile lines =
let val fd = TextIO.openAppend filePath
in List.app (fn s => TextIO.output (fd, s^"\n")) lines
; TextIO.closeOut fd
end
(Предложение) Наконец, вы можете вызывать эту функцию appendListToFile
, или просто appendLines
и возьмите filePath
в качестве аргумента функции, так как filePath
подразумевает, что это файл, и функция добавляет линейные разрывы к каждому s
. Имена важны.
fun appendLines filePath lines =
let val fd = TextIO.openAppend filePath
in List.app (fn s => TextIO.output (fd, s^"\n")) lines
; TextIO.closeOut fd
end
У вас есть много терпения. Удивительно, что SML/NJ, похоже, попадает во внутреннюю ошибку при компиляции этого кода, а не просто отказывается от него с помощью диагностического сообщения. –
Хе-хе, спасибо. Трудно дать подробное сообщение об ошибке при сбое анализа. Кажется, что Java/C# IDE лучше справляются с этим во многих случаях; кажется, что они могут возобновить анализ за точкой отказа и предоставить частичное синтаксическое дерево. Я не знаю, как это делается на этом. –
Хмм, пытаясь передать в 'filePath' и' args', дает мне 'Ошибка: оператор не является функцией [tycon mismatch] operator: unit', любая идея, почему это может быть? Сообщения об ошибках SML очень сбивают меня с толку –