Я новичок в ML, но в других языках, использующих вывод типов, я усвоил привычку опускать тип вещи всякий раз, когда вывод в правой части очевиден для читателя, и явно объявлять тип объекта. вещь всякий раз, когда вывод не очевиден для человека. Мне нравится это соглашение, и я хотел бы продолжить использовать его в своем коде ML.
У меня есть следующие примеры объявлений функций, которые эквивалентны:
fun hasFour [] = false
| hasFour (x::xs) = (x = 4) orelse hasFour xs
эквивалентно
val rec hasFour: int list -> bool =
fn [] => false
| (x::xs) => (x = 4) orelse hasFour xs
Мне нравится последняя форма не только потому, что мне легче понять, какого типа функция, когда я ее читаю, но и потому, что она явно объявляет тип функции, и, следовательно, если я что-то напортачу в своей реализации, нет шансов случайно объявить что-то синтаксически допустимое, но неправильный тип, который потом будет труднее отлаживать.
Мой вопрос: я хочу использовать fun
вместо val rec
, потому что анонимные fn
могут принимать только один параметр. Таким образом, последний метод синтаксически недействителен для такой функции, как int -> int -> bool
. Есть ли способ явно объявить тип в fun
? Или я назвал все предпочтительные альтернативы в этом посте и должен просто следовать одному из этих шаблонов? Единственный способ использовать fun
с явным объявлением типа — это добавить объявление типа к каждому параметру в шаблоне, что довольно уродливо и ужасно, например:
fun hasFour ([]:int list):bool = false
| hasFour (x::xs) = (x = 4) orelse hasFour xs
Коллега показал мне код, следующий по такому шаблону:
fun hasFour [] = false
| hasFour (x::xs) = (x = 4) orelse hasFour xs
val _ = op hasFour: int list -> bool
Объявляя безымянную переменную и присваивая ей экземпляр функции с принудительным типом, мы эффективно достигаем желаемого результата, но val _
должна выглядеть как ниже полностью определенной функции, где это менее очевидно для человека-читателя, если только вы просто не получите привыкли к этому шаблону и научились его ожидать.
Недавно я задал очень похожий вопрос, Могу ли я аннотировать полный тип объявления fun
?.
Ваше текущее решение было бы хорошим ответом на это.
У вас может быть несколько каррированных аргументов с несколькими fn
, например. подобно:
val rec member : ''a -> ''a list -> bool =
fn x => fn [] => false
| y::ys => x = y orelse member x ys
Или вы можете сделать так, как делаете сейчас, или как предлагает Мэтт:
local
fun member _ [] = false
| member x (y::ys) = x = y orelse member x ys
in
val member = member : ''a -> ''a list -> bool
end
Но комбинация использования fun
и наличия полной подписи типа в списке первым пока неуловима.
Для производственного кода нормой является сбор сигнатур типов в подпись модуля. См. ML для работающего программиста, гл. 7: Подписи и абстракция, стр. 267-268. Хотя я предполагаю, что тогда вы захотите использовать Ocaml.