我有一个数据类型:
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'可以包含其他未计入的叶子和树干。请注意,这不是递归的。我一直在考虑尝试使用延续,但我不知道该怎么做。 有什么建议吗?
答案 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!