Trie-Set的可折叠实例

时间:2015-11-02 01:02:22

标签: haskell trie foldable

我有一个类似于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的{​​em>种,如下所示:

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 :))

但我无法找出Foldable的{​​{1}}个实例。 Trie似乎具有所有必要的功能,但我无法弄清楚类型。

以下是我正在寻找的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 :)) ,所以它将它存储的列表视为每个元素?该数据结构的类型是什么样的?

1 个答案:

答案 0 :(得分:4)

这可能是您想要做的事情,但您可以将通用数据结构包装到GADT中,该GADT只允许将列表存储在叶子上。为简单起见,使用树而不是Tries的简单示例:假设通用数据结构为Tree,并且我们希望使LTree仅允许列表树:

{-# LANGUAGE GADTs #-}

import Prelude hiding (foldr)
import Data.Foldable
import Data.Tree

foldrForListTrees :: ([a] -> b -> b) -> b -> Tree [a] -> b
foldrForListTrees = error "This is the one you are supposed to be able to write"

data LTree a where
    MkLTree :: Tree [a] -> LTree [a]

instance Foldable LTree where
    foldr f ys0 (MkLTree xs) = foldrForListTrees f ys0 xs