我有一个类似Set的数据结构,是用Trie实现的,定义如下:
import qualified Data.Map as M
import Data.Foldable (Foldable, foldr)
import Prelude hiding (foldr)
import Data.Maybe (fromMaybe)
data Trie a = Trie { endHere :: Bool
, getTrie :: M.Map a (Trie a)
} deriving (Eq)
有一个如下的插入操作:
insert :: (Ord a, Foldable f) => f a -> Trie a -> Trie a
insert = foldr f (\(Trie _ m) -> Trie True m) where
f e a = overMap (M.alter (Just . a . fromMaybe (Trie False M.empty)) e)
overMap :: Ord b => (M.Map a (Trie a) -> M.Map b (Trie b)) -> Trie a -> Trie b
overMap f (Trie e m) = Trie e (f m)
我可以得到一种类似于这样的foldr
:
而且我可以将其改进,使其更加易懂:
foldrTrie :: ([a] -> b -> b) -> b -> Trie a -> b
foldrTrie f i (Trie a m) = M.foldrWithKey ff s m where
s = if a then f [] i else i
ff k = flip (foldrTrie $ f . (k :))
但我无法弄清楚Trie
的Foldable
实例。 foldrTrie
似乎具有所有必要的功能,但我只是无法弄清楚类型。
这里是我正在寻找的foldr
行为的示例:
fromList :: (Ord a, Foldable f, Foldable g) => f (g a) -> Trie a
fromList = foldr insert (Trie False M.empty)
toList :: (Ord a) => Trie a -> [[a]]
toList = foldr (:) [] -- replace foldr here with foldrTrie and you'll get the
-- desired behaviour
toList (fromList ["abc", "def"]) -- ["abc","def"]
我无法处理的是Foldable
的类型注释:
instance Foldable Trie a where
我尝试让我的Trie
有第二个类型参数:
data Trie a (f a) = Trie { endHere :: Bool
, getTrie :: M.Map a (Trie a (f a))
} deriving (Eq)
为了我能够做到像这样的事情:
instance Foldable Trie a f where
foldr f i (Trie a m) = M.foldrWithKey ff s m where
s = if a then f [] i else i
ff k = flip (foldrTrie $ f . (k :))
但我无法确定这些类型。
更一般地说,可以这样表述问题:如果我有一个只能存储列表的数据结构,我是否能够在该数据结构上定义foldr
函数,以使其将存储的列表视为每个元素?那么这种数据结构的类型会是什么样子呢?
Foldable
)的Ord
元素。存储在Trie
中的东西必须是Foldable
,因为这是将某些东西插入到Trie
中的唯一方法。我希望能够再次使用foldr
访问Trie
中的内容,保留它们类似于序列的结构。 - oisdkFoldable
是如何做到的。仅使用Foldable
接口到Trie
,我看不到编写所需函数的方法,因为Foldable
简单地不能这样做。foldrTrie
比foldr : (a -> b -> b) -> b -> Trie a -> b
更通用。 - user2407038Foldable
?机制方面我可以搞定(我想);但是类型却限制了我。那么这个数据结构的类型签名会是什么样子呢? - oisdk