一种选择是使用elem
,它检查值是否是Foldable
容器的元素。
treeLook :: Eq a => a -> TernaryTree a -> Bool
treeLook = elem
现在你只需要写一个Foldable
. 一种选择是启用DeriveFoldable
扩展并仅用于deriving (Show, Foldable)
让 GHC 为您编写实例。但是那样你不会学到很多东西。因此,让我们探索一些方法来做到这一点。
-- This import is needed for non-bleeding-edge GHC versions.
import Data.Monoid ((<>))
instance Foldable TernaryTree where
-- Fold over the tree in pre-order
foldMap _ EmptyTree = mempty
foldMap f (Node x ls cs rs) =
f x <> foldMap f ls <> foldMap f cs <> foldMap f rs
但是这种重复foldMap
本身就是一种“模式”,您可以通过为树编写“catamorphism”来提取:
cataTree :: r -> (a -> r -> r -> r -> r) -> TernaryTree a -> r
cataTree e _ EmptyTree = e
cataTree e f (Node x ls cs rs) =
f x (cataTree e f ls) (cataTree e f cs) (cataTree e f rs)
现在您可以foldMap
这样定义:
foldMap f = cataTree mempty (\a lr cr rr -> f a <> lr <> cr <> rr)
现在foldMap
自己有了一个更厉害的表弟,traverse
。所以另一种选择是从那里开始:
import Data.Traversable (fmapDefault, foldMapDefault)
instance Traversable TernaryTree where
-- Traverse the tree in pre-order
traverse f =
cataTree (pure EmptyTree)
(\a ls cs rs -> Node <$> f a <*> ls <*> cs <*> rs)
instance Functor TernaryTree where
fmap = fmapDefault
instance Foldable TernaryTree where
foldMap = foldMapDefault
显然,您不会想要做任何花哨的事情,但是一旦您想要快速生成一堆函数,这些技术实际上是有用的。