非递归地计算数据类型

时间:2014-10-27 13:13:15

标签: recursion sml smlnj

我有一个数据类型:

datatype int A = leaf of int * string
               | trunk of int * (int A) list

说我是否有测试:int A,然后我想计算测试中的叶子和树干并将它们作为一对返回:(#leafs,#trunk)。但是我不想使用递归。

这是我的尝试:

  fun count(test: int A): int*int =
      case test
         of trunk(a,l) =>
            let
               val l1 = List.filter(fn trunk(a',l') => true
                                     | _ => false) l
               val l2 = List.filter(fn leaf(a',s) => true
                                     | _ => false) l
            in
               (List.length(l2), List.length(l1) + 1)
            end
          | leaf(a,s) => (1, 0)

只要l'没有。如您所见,我将发束和中继分成不同的列表并返回长度。 但是,l'可以包含其他未计入的叶子和树干。请注意,这不是递归的。我一直在考虑尝试使用延续,但我不知道该怎么做。 有什么建议吗?

1 个答案:

答案 0 :(得分:1)

由于我们的数据类型与列表不同,我们需要为它创建一个显式的reduce函数。此reduce函数接收应用于每个叶子的函数(ff)。它还接受一个应用于每个主干的函数(fd)并递归地组合结果。它看起来像这样:

  fun reduce(ff:('a*string -> 'b))(fd:('a * 'b list -> 'b))(s: int A): 'b =
      case s
         of leaf(a, d) => ff(a,d)
          | trunk(a, l)  => fd(a, List.map(fn x => reduce(ff)(fd)(x)) l)

最后我们的计数功能将如下所示:

  

fun count(s:int A):int * int =

  let
     val i = reduce(fn x => 1)(fn (y,l) => foldr op+ 0 l)(s)
     val i' = reduce(fn x => 0)(fn (y,l) => 1 + foldr op+ 0 l)(s)
  in
     (i, i')
  end

也就是说,在(i)中如果找到一个叶子,则将其替换为1,如果找到一个树干,则将其替换为0并将整个列表相加。 在(i')中,如果找到一个叶子,则将其替换为0.否则,如果找到一个主干并加上1,则加1!