SML,递归数据类型数组

SML, recursing a datatype array

我有这个数据类型

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")

和 return 在 string "foo" 上匹配,在 Array 中搜索每个 Object。正如您在代码中看到的那样,我实际上只处理 json 中符合匹配条件的两件事,即包含 ObjectsArray,然后发送 Objects 待检查。这段代码有效,但它肯定来自粗野主义的编程学派,也就是说,它感觉像是一种拼凑。为什么?由于 mymatch 中的情况,我需要通过 Array

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

到现在为止,我只处理了列表上的递归,您在其中检查汽车,然后在 cdr 上递归。同样,此代码有效,但我能感觉到我遗漏了一些东西。我需要检查 Array 的头部 Object 并在匹配时终止;否则,继续递归 - 全部在 option return 世界中。有更优雅的方法吗?

写一个函数来匹配数组的"innards":

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);