Функция SML в качестве справочной таблицы - PullRequest
0 голосов
/ 03 апреля 2020

Изучая типы в SML, я нашел это

fun monthI2S 1 = "January"
  | monthI2S 2 = "February"
  | monthI2S 3 = "March"
  | monthI2S 4 = "April"
  | monthI2S 5 = "May"
  | monthI2S 6 = "June"
  | monthI2S 7 = "July"
  | monthI2S 8 = "August"
  | monthI2S 9 = "September"
  | monthI2S 10 = "October"
  | monthI2S 11 = "November"
  | monthI2S 12 = "December"

, которое для меня выглядит как функция, которая служит таблицей поиска. (На самом деле я даже не уверен, как называется этот стиль функции SML. Она выглядит как Haskell формула индукции?) Был бы способ не получить «неисчерпывающее» предупреждение, если учесть случаи, когда ввод <= 0 orelse > 12?

fun monthI2S m = if m <= 0 orelse M > 12 then NONE else ...?
  | monthI2S 1 = "January"
  | monthI2S 2 = "February"
  | monthI2S 3 = "March"
  | monthI2S 4 = "April"
...

, очевидно, не работает, потому что я не могу согласовать else с | .... Или я просто лаю не на то дерево и должен просто использовать case -подобный подход?

1 Ответ

2 голосов
/ 03 апреля 2020

Сопоставление с образцом происходит от самого верхнего предложения до самого нижнего, поэтому вы хотите, чтобы самый общий случай был последним.

fun monthI2S 1 = "January"
  | monthI2S 2 = "February"
  ...
  | monthI2S m = nothing else matched, so m must be < 1 or > 12...

Теперь, как вы справитесь с ошибкой, зависит от вас.

Тривиальное и наименее надежное решение - просто вернуть "Неверный номер месяца" или что-то в этом роде.

Вы также можете вызвать исключение или использовать Option.

Если вы используете последнее, я бы лично переписал с локальной функцией, чтобы избежать разбрасывания SOME повсюду:

fun monthI2S m = let
    fun monthI2S_safe 1 = "January"
      | monthI2S_safe 2 = "February"
      | monthI2S_safe 3 = "March"
      | monthI2S_safe 4 = "April"
      | monthI2S_safe 5 = "May"
      | monthI2S_safe 6 = "June"
      | monthI2S_safe 7 = "July"
      | monthI2S_safe 8 = "August"
      | monthI2S_safe 9 = "September"
      | monthI2S_safe 10 = "October"
      | monthI2S_safe 11 = "November"
      | monthI2S_safe 12 = "December"
      | monthI2S_safe _ = "Can never happen" 
in
    if m >= 1 andalso m <= 12 then SOME (monthI2S_safe m) else NONE
end;
...