Учитывая функциональную структуру данных (в данном случае, дерево), обычно вы можете сделать с ней две общие вещи.
- карта
- складка
Mapping где вы берете функцию f :: a -> b
и структуру origTree :: Tree a
и применить функцию к элементам конструкции, в результате чего newTree :: Tree b
. (Заметим, что канонический способ сделать структуру назначаемыми, чтобы сделать его Functor
, и определить fmap
)
Складные где вы как-то соединение всех элементов структуры в какой-то новое значение. Когда вы сказали, что у вас есть Tree
и функция (+)
, я сразу же подумал о сгибе: суммируя все элементы в дереве. (Заметим, что канонический способ сделать структуру Складная, чтобы сделать его экземпляр Foldable
(сюрприз!) И определить foldMap
или foldr
)
Однако представляется, ваша домашняя задача состоит в том, чтобы определить функцию отображения для вашего дерева.
Теперь, касаясь вашего собственного вопроса, превращая функцию в дерево. Немного непонятно, что именно вы имеете в виду, поставив a
, b
и c
в свое дерево, но давайте немного поиграем с этой идеей. Для простоты я не собираюсь делать полностью общую функцию. Кроме того, поскольку ваши функции «деревья» довольно однобокие, я называю их FunHistory
вместо Tree
. Это будет представлять историю приложений функций.
data FunHistory a b = Result b (FunHistory a b)
| Application (a -> FunHistory a b) a (FunHistory a b)
| Base (a -> FunHistory a b)
Теперь этот тип немного странный.Result
содержит результат типа b
, а также ссылку на предыдущий история применения функций. Base
содержит функцию с no история функциональных приложений и возможность , производя будущую историю, если предоставляется значение типа a
. Таким образом, Application
является промежуточной записью, которая обеспечивает возможность создания будущей истории, а также отмечает прошлую историю и значение которой было применено к этой прошлой истории.
Теперь давайте сделаем некоторые функции для удобства. Ремень на ремне безопасности, это может стать ухабистым.
mkHist :: (a -> b) -> FunHistory a b
mkHist f = let h = Base (\x -> Result (f x) h) in h
Учитывая функцию с одним аргументом, мы можем создать историю из нее магией. Этот особый аромат магии называется «лень» и «рекурсивный пусть».
Давайте перейдем и создадим функцию, которая примет значение FunHistory
и значение ввода, и переместите историю. К сожалению, это не полная функция; он не определен для Result
типа FunHistory
.
-- The caller should make sure it isn't a `Result` type before using this function
app :: a -> FunHistory a b -> FunHistory a b
app x (Result _ _) = undefined
app x (Application f _ _) = f x
app x (Base f) = f x
Это прекрасно и денди для функций одного аргумента, но промежуточный Application
конструктор никогда не требуется для таких простых случаев. Давайте попробуем создать смарт-конструктор для функции 2-аргумента:
mkHist2 :: (a -> a -> b) -> FunHistory a b
mkHist2 f = let h = Base (\x -> mkHist' f x h)
in h
mkHist' f x h = let h' = Application (\y -> Result (f x y) h') x h
in h'
Давайте попробуем для функции 3-аргумента теперь:
mkHist3 :: (a -> a -> a -> b) -> FunHistory a b
mkHist3 f = let h = Base (\x -> mkHist2' f x h)
in h
mkHist2' f x h = let h' = Application (\y -> mkHist' (f x) y h') x h
in h'
Теперь 4-аргумент функции:
mkHist4 :: (a -> a -> a -> b) -> FunHistory a b
mkHist4 f = let h = Base (\x -> mkHist3' f x h)
in h
mkHist3' f x h = let h' = Application (\y -> mkHist2' (f x) y h') x h
in h'
Хорошо посмотрите на это; эти функции выглядят почти точно как mkHist3
и mkHist2'
соответственно! Следующим шагом здесь было бы обобщить эти функции на класс, чтобы он масштабировался до функций с произвольным количеством входов. Уловка состоит в том, что все входы должны иметь один и тот же тип.
[предупреждение: этот код не тестировался, но я несколько уверен, что это в основном правильно ... иш]
instance (Show a, Show b) => Show (FunHistory a b) where
show (Base _) = "base"
show (Application _ x h) = "app " ++ show x ++ ", " ++ show h
show (Result r h) = "result: " ++ r ++ ", " ++ show h
Люди будут более вероятно, чтобы помочь вам, если вы покажете попытку решения, особенно для домашней проблемы. –
Thx, я пробовал несколько часов, но мне не нравится размещать мой мусор здесь. Знаете, это либо 1, либо 0 – manuzhang
Что такое '(+) a b' в контексте двоичного дерева с одним значением в каждом его узле? –