Вы говорите, что ваш код не дает правильного ответа, но вы не говорите, какой ответ вы получите, и почему это не правильно.Так что, возможно, в вашем коде есть ошибка, или вы обходите дерево в другом порядке, чем вы хотите.Если бы я узнал, я бы немного переформатировал ваш код:
fun treeReduce g z0 Empty = z0
| treeReduce g z0 (Node (left, x, right)) =
let val z1a = treeReduce g z0 left
val z1b = treeReduce g z0 right
val y = g (z1a, x)
val z = g (z1b, y)
in z end
Я использовал let-in-end , чтобы более точно дать каждому вычислению имя.
Одна вещь, которая кажется мне странной, это то, что z1a
и z1b
оба основаны на z0
.Сравните это с реализацией обхода деревьев в SML для предварительного заказа, по порядку и после заказа, и вы увидите, что вы, вероятно, хотите, чтобы накопленное значение перемещалось по каждому узлу.В вашем случае z1a
не переносится в ветку right
.
Еще одна вещь, которая мне кажется странной, - это подпись типа treeReduce
:
('a * 'a -> 'a) -> 'a -> 'a tree -> 'a
Сравните это с treefold_preorder
s:
('a * 'b -> 'b) -> 'b -> 'a tree -> 'b
и ради этого List.foldl
s:
('a * 'b -> 'b) -> 'b -> 'a list -> 'b
Это позволяет накопительной функции производитьзначения произвольного типа 'b
вместо возможности создания значений типа узла дерева 'a
.Это, предположительно, случайное изменение вызвано передачей выходных данных g
себе:
g(g(tree..., x), tree...)
, заставляя его входное значение (тип узла, 'a
) иметь тот же тип, что и его выходное значение.
Что я делаю не так?
Вы неправильно соединяете левый и правый вызовы на treeReduce
, и вы получаетеодин вызов g
слишком много (при попытке склеить левый и правый вызовы treeReduce
), в результате чего он будет иметь тип 'a * 'a -> 'a
, если вы хотите, чтобы он имел тип 'a * 'b -> 'b
или аналогичный.
Поскольку вы складываете деревья, это может представлять интерес: