这是在我的代码中声明Trie数据结构的方式:
data Trie = MakeTrie Char [Trie]
现在我必须编写一个名为countChar的函数,它接收一个Trie和一个目标值(Char类型)并计算目标值在Trie中出现的次数。
这是我写的代码:
countChar :: Trie -> Char -> Integer
countChar (MakeTrie root []) target
| root == target = 1
| otherwise = 0
countChar (MakeTrie root children) target
| root == target = 1 + ...
| otherwise = 0 + ...
最初我想做一些像这样映射函数的东西:
...otherwise = 0 + foldr1 (+) (map count children target)
where
count = countChar t c
但是我认为这样做不正常,现在我或多或少都不知道该做什么才能使功能发挥作用。
答案 0 :(得分:4)
定义Trie
的一种稍微“有趣”的方式是
type Trie = Cofree [] Char
这为我们提供了免费Foldable
个实例,因为[]
是Foldable
。我们也可以在deriving Foldable
的数据转换中添加Trie
。
这意味着我们可以:
countChar :: (Eq a,Num n,Foldable t) => a -> t a -> n
countChar c = foldr (\c' a -> if c == c' then a + 1 else a) 0
如果您愿意,该类型签名可以专门用于Char -> Trie -> Integer
。 (使用a ~ Char
,t ~ Cofree []
,n ~ Integer
)
您也可以使用Sum
:
countChar :: (Eq a,Num n,Foldable t) => a -> t a -> n
countChar c = getSum . foldMap (\c' -> if c == c' then Sum 1 else Sum 0)
故事的道德:利用类型类和其他现有机制来回避样板并概括你的代码。
答案 1 :(得分:2)
如果您可以将方法的签名更改为countChar :: Char -> Trie -> Integer
,那么您可以执行此操作:
countChar :: Char -> Trie -> Integer
countChar target (MakeTrie root children)
| root == target = (1 + sum(map (countChar target) children))
| otherwise = (0 +sum(map (countChar target) children))
这样您就可以在map
列表中使用Trie
。
例如,给定countChar 'A' (MakeTrie 'A' [MakeTrie 'B' [MakeTrie 'A' [] ], MakeTrie 'C' []])
,它将返回2.