SML, рекурсивный массив типов данных - PullRequest
1 голос
/ 13 апреля 2020

У меня есть этот тип данных

datatype json =
    Num of real
    | String of string
    | False
    | True
    | Null
    | Array of json list
    | Object of (string * json) list

и этот код

fun mymatch (jobj,str) = 
    case jobj of
        Array [] => NONE
      | Array(Object oh::[]) => mymatch (Object oh, str)
      | Array (Object oh::ot) => 
           if isSome (assoc(str, oh)) then assoc(str, oh) else mymatch (Array ot, str)
      | Object xs => assoc (str, xs)
      | _ => NONE

с этой вспомогательной функцией

fun assoc (k, ls) =
    case ls of
        [] => NONE
      | (a,b)::[] => if k = a then SOME b else NONE
      | (a,b)::xs => if k = a then SOME b else assoc (k,xs)

, которая должна принимать что-то вроде этого

mymatch (Array [Object [("n", Num (4.0)),("b", True)],Object [("last", Num (4.0)),("foo", True)]],"foo")

и верните совпадение в string «foo», ища каждый Object в Array. Как вы можете видеть в коде, я на самом деле обрабатываю только две вещи в json, которые соответствуют критериям, то есть Array, который содержит Objects с, затем отправка Object s для проверки , Этот код работает, но он наверняка из бруталистической школы программирования, т. Е. Он выглядит как клудж. Почему? Из-за случая в mymatch, когда мне нужно пройти через Array

...
| Array (Object oh::ot) => 
     if isSome (assoc(str, oh)) then assoc(str, oh) else mymatch (Array ot, str)
...

До сих пор я имел дело только с рекурсией в списках, где вы проверяете автомобиль, а затем выполняете рекурсию на корд. Опять же, этот код работает, но я чувствую, что что-то упустил. Мне нужно проверить голову Object из Array и завершить, если она совпадает; в противном случае продолжайте повторять - все в мире возвращения option. Есть ли более элегантный способ сделать это?

1 Ответ

1 голос
/ 14 апреля 2020

Напишите функцию для сопоставления "внутренних" массивов:

fun match_array (str, Object ob :: obs) = (case assoc (str, ob) of
                                               NONE => match_array (str, obs)
                                             | something => something)
  | match_array _ = NONE;

, затем переписайте mymatch:

fun mymatch (str, Array a) = match_array (str, a)
  | mymatch (str, Object ob) = assoc (str, ob)
  | mymatch _ = NONE;

Вы также можете немного упростить assoc:

fun assoc (k, []) = NONE
  | assoc (k, (a,b)::xs) = if k = a then SOME b else assoc (k,xs);
...