Haskell - 没有树的霍夫曼解码
Haskell - Huffman Decoding without tree
因此,对于给我的作业,我需要完成三个函数,即从给定树的每个叶节点中提取 HCodeMap,将字符串编码为位列表,以及对其进行解码一串比特回到一个字符串。
我已经成功完成了代码提取和编码功能,但我正在努力进行最后一个解码功能,因为我们不允许遍历树,因为我们没有使用。
这是函数的格式,后面是我们提供的一些类型:
decode :: [Bit] -> HCodeMap -> Maybe String
data Bit = Zero | One deriving (Show, Eq)
type HCodeMap = [(Char, [Bit])]
我最初尝试创建自己的查找函数,它会交换 HCodeMap 的值,然后从给定的位列表中查找前 n 位。
没说清楚我再举个例子来说明:
[Bit] 我们得到:[一,零,一,一,零]
HCodeMap 我们得到:[('c',[Zero]),('a',[One,Zero]),('b',[一,一])]
我计划从列表中获取我们给出的第一位,即 One,然后通过 HCodeMap 测试进行搜索,看看它是否等于那里的任何 [Bit]。
这是我的反向查找功能的用武之地,因为我可以查找 HCodeMap 中的位列表,因为我不能按字母查找。它是沿着:
lookup (bits we given here) (HCodeMap的每个元组) $ map swap code
在这种情况下,我们看到 One 不匹配任何 HCodeMap 元组,因此我随后测试 One,Zero。这与 'a' 相匹配,所以我将 'a' 添加到一个字符串中,然后继续下一个 [Bit] 我们通过了,再次成为 One。
等等等等这一切继续下去,我们只剩下字符串 "abc".
然而,我真的很纠结于如何将它实际放入一个函数中。
我希望我没有让这太混乱,提前感谢您的帮助!
尝试依次解析所有代码,然后在成功匹配后重复。重复直到没有更多输入。
import Control.Monad
data Bit = Zero | One deriving (Show, Eq)
type HCodeMap = [(Char, [Bit])]
decode :: [Bit] -> HCodeMap -> Maybe String
decode bits codes = process bits where
-- if the code matches the input, return the corresponding
-- Char value along with the rest of of the input
match :: (Char, [Bit]) -> [Bit] -> Maybe (Char, [Bit])
match (v, xs) ys = go xs ys where
go (x:xs) (y:ys) | x == y = go xs ys
go [] ys = Just (v, ys)
go _ _ = Nothing
-- match and consume until there's no more input, or fail if there is no match.
-- note that msum takes the first Just from a list of Maybe-s,
-- or returns Nothing if there isn't any
process :: [Bit] -> Maybe String
process [] = Just []
process xs = do
(v, xs) <- msum $ map (`match` xs) codes
(v:) `fmap` process xs
对于那些不熟悉 msum
的人,这里是专门针对 Maybe
的实现:
msum :: [Maybe a] -> Maybe a
msum (Just a:xs) = Just a
msum (Nothing:xs) = msum xs
msum [] = Nothing
因此,对于给我的作业,我需要完成三个函数,即从给定树的每个叶节点中提取 HCodeMap,将字符串编码为位列表,以及对其进行解码一串比特回到一个字符串。
我已经成功完成了代码提取和编码功能,但我正在努力进行最后一个解码功能,因为我们不允许遍历树,因为我们没有使用。
这是函数的格式,后面是我们提供的一些类型:
decode :: [Bit] -> HCodeMap -> Maybe String
data Bit = Zero | One deriving (Show, Eq)
type HCodeMap = [(Char, [Bit])]
我最初尝试创建自己的查找函数,它会交换 HCodeMap 的值,然后从给定的位列表中查找前 n 位。
没说清楚我再举个例子来说明:
[Bit] 我们得到:[一,零,一,一,零]
HCodeMap 我们得到:[('c',[Zero]),('a',[One,Zero]),('b',[一,一])]
我计划从列表中获取我们给出的第一位,即 One,然后通过 HCodeMap 测试进行搜索,看看它是否等于那里的任何 [Bit]。
这是我的反向查找功能的用武之地,因为我可以查找 HCodeMap 中的位列表,因为我不能按字母查找。它是沿着:
lookup (bits we given here) (HCodeMap的每个元组) $ map swap code
在这种情况下,我们看到 One 不匹配任何 HCodeMap 元组,因此我随后测试 One,Zero。这与 'a' 相匹配,所以我将 'a' 添加到一个字符串中,然后继续下一个 [Bit] 我们通过了,再次成为 One。
等等等等这一切继续下去,我们只剩下字符串 "abc".
然而,我真的很纠结于如何将它实际放入一个函数中。
我希望我没有让这太混乱,提前感谢您的帮助!
尝试依次解析所有代码,然后在成功匹配后重复。重复直到没有更多输入。
import Control.Monad
data Bit = Zero | One deriving (Show, Eq)
type HCodeMap = [(Char, [Bit])]
decode :: [Bit] -> HCodeMap -> Maybe String
decode bits codes = process bits where
-- if the code matches the input, return the corresponding
-- Char value along with the rest of of the input
match :: (Char, [Bit]) -> [Bit] -> Maybe (Char, [Bit])
match (v, xs) ys = go xs ys where
go (x:xs) (y:ys) | x == y = go xs ys
go [] ys = Just (v, ys)
go _ _ = Nothing
-- match and consume until there's no more input, or fail if there is no match.
-- note that msum takes the first Just from a list of Maybe-s,
-- or returns Nothing if there isn't any
process :: [Bit] -> Maybe String
process [] = Just []
process xs = do
(v, xs) <- msum $ map (`match` xs) codes
(v:) `fmap` process xs
对于那些不熟悉 msum
的人,这里是专门针对 Maybe
的实现:
msum :: [Maybe a] -> Maybe a
msum (Just a:xs) = Just a
msum (Nothing:xs) = msum xs
msum [] = Nothing