【问题标题】:Foldable instance for a Trie-SetTrie-Set 的可折叠实例
【发布时间】:2015-11-02 01:02:21
【问题描述】:

我有一个类似 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 :))

但我不知道TrieFoldable 实例。 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 :))

但我无法弄清楚类型。

一个更通用的问题框架可能是这样的:如果我有一个可以存储 only 列表的数据结构,我是否能够在该数据结构上定义foldr,所以它将它存储的列表视为每个元素?该数据结构的类型是什么样的?

【问题讨论】:

  • instance Foldable Trie where foldr f = foldrTrie $ flip $ foldr f。我看不出为什么“Trie 只能存储可折叠的东西”。
  • 此 Trie 旨在作为一种数据结构来存储 Ord 元素的序列(或更一般地说,Foldables)。存储在Trie 中的东西必须Foldable,因为这是向Trie 插入东西的唯一方法。我希望能够使用foldr 再次访问Trie 中的内容,并保留它们类似序列的结构。
  • 我确信有很多方法可以表示一个序列,但我看不到Foldable 是如何做到的。仅使用TrieFoldable 接口,我认为没有办法编写您想要的函数,因为Foldable 根本不会这样做。 foldrTriefoldr : (a -> b -> b) -> b -> Trie a -> b 更通用。
  • 我想我要问的是,如果我有一个可以存储only(比如)列表的数据结构,我可以在该数据结构上实现Foldable 吗?我可以管理机制(我认为);但这是阻碍我的类型。该结构的类型签名是什么样的?

标签: haskell trie foldable


【解决方案1】:

这可能不是您想要做的,但是您可以将通用数据结构包装到 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

【讨论】:

  • 在这种情况下,也可以直接将Trie 定义为这样的GADT,代价是在其类型参数周围到处添加[]
  • 我认为这实际上可能是一个非常好的选择。无论如何,我本来打算对 Trie 进行更多概括(即,将其作为映射结构,通过将 endHere 替换为 Bool 以外的类型),所以我可能有一个 STrie GADT(使用 @ 987654329@ 到处都是其类型参数),然后是另一个 Trie ,它可以以不同的方式实现 Foldable 。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 2013-03-13
  • 1970-01-01
相关资源
最近更新 更多