String Haskell树构造

String Haskell树构造,string,haskell,tree,huffman-code,String,Haskell,Tree,Huffman Code,需要一些帮助来编写接受字符串并创建二叉树的Haskell函数。需要有更好的Haskell经验的人帮助我填补一些漏洞,并说明原因,因为这对我来说是一次学习经历 我在Haskell的一个项目中得到了一个用单个字符串编码的树(例如**B**DECA)。星形表示节点,其他字符表示叶。我试图用从输入中读取的信息填充这个数据结构 data-Trie=Leaf-Char | Branch-Trie-Trie 我更喜欢数学和命令式编程,所以我观察到我可以通过从左到右解析来定义子树。正确的树将比*多1个字符。从数

需要一些帮助来编写接受字符串并创建二叉树的Haskell函数。需要有更好的Haskell经验的人帮助我填补一些漏洞,并说明原因,因为这对我来说是一次学习经历

我在Haskell的一个项目中得到了一个用单个字符串编码的树(例如
**B**DECA
)。星形表示节点,其他字符表示叶。我试图用从输入中读取的信息填充这个数据结构

data-Trie=Leaf-Char | Branch-Trie-Trie

我更喜欢数学和命令式编程,所以我观察到我可以通过从左到右解析来定义子树。正确的树将比
*
多1个字符。从数学上讲,我会想到一个递归结构

如果第一个字符不是
*
,则解决方案是第一个字符。否则,解决方案是一个分支,其中子分支被反馈到函数中,其中左分支是第一组字符,其中字符超出编号
*
,右分支是其他所有字符

constructTrie :: String -> Trie
constructTrie x = if x !! 1 == '*' then
                      let leftSubtree = (first time in drop 1 x where characters out number *'s)
                          rightSubtree = (rest of the characters in the drop 1 x)
                      in Branch constructTrie(leftSubtree) constructTrie(rightSubtree)
                  else Leaf x !! 1
大多数情况下,我需要帮助定义左子树和右子树,以及这样定义是否有任何错误。

(顺便说一下,它是
0
-索引的)通常是不可能的。这是一件非常“必要”的事情,而且像这里这样的常数指数特别难闻。这意味着你真的想要一个模式匹配。此外,在索引处拆分列表(
type String=[Char]
)并分别对这两个部分进行操作是一个坏主意,因为这些列表是链接且不可变的,因此最终会复制整个第一部分

您希望这样做的方式如下所示:

  • 如果字符串为空,则失败
  • 如果它以一个
    *
    开头,那么做一些事情,以某种方式解析左边的子树,并在一个步骤中获得列表的其余部分,然后从剩余部分中解析右边的子树,形成一个
    分支
  • 如果它是另一个字符,则制作一个
无需找出拆分字符串的位置,实际拆分字符串,然后解析一半;只要解析列表,直到你不能再解析了,然后剩下的(或者我应该说是对的?)就可以再次解析了

因此:定义一个函数
constructTrie'::String->Maybe(Trie,String)
,该函数将
字符串的开头消耗为
Trie
,然后保留未解析的位(如果解析失败,则不提供任何内容)。此函数将是递归的,这就是它获得额外输出值的原因:它需要额外的管道来移动列表的其余部分
constructTrie
本身可以定义为其周围的包装:

-- Maybe Trie because it's perfectly possible that the String just won't parse
constructTrie :: String -> Maybe Trie
constructTrie s = do (t, "") <- constructTrie' s
                  -- patmat failure in a monad calls fail; fail @Maybe _ = Nothing
                     return t

-- can make this local to constructTrie in a where clause
-- or leave it exposed in case it's useful
constructTrie' :: String -> Maybe (Trie, String)
constructTrie' "" = Nothing -- can't parse something from nothing!
constructTrie' ('*':leaves) = do (ln, rs) <- constructTrie' leaves
                              -- Parse out left branch and leave the right part
                              -- untouched. Doesn't copy the left half
                                 (rn, rest) <- constructTrie' rs
                              -- Parse out the right branch. Since, when parsing
                              -- "**ABC", the recursion will end up with
                              -- constructTrie' "*ABC", we should allow the slop.
                                 return (Branch ln rn, rest)
constructTrie' (x:xs) = return (Leaf x, xs)
--可能是Trie,因为字符串很可能无法解析
constructTrie::String->Maybe Trie
constructrie s=do(t,“”)
(顺便说一下,它是
0
-索引的)通常是不可能的。这是一件非常“必要”的事情,而且像这里这样的常数指数特别难闻。这意味着你真的想要一个模式匹配。此外,在索引处拆分列表(
type String=[Char]
)并分别对这两个部分进行操作是一个坏主意,因为这些列表是链接且不可变的,因此最终会复制整个第一部分

您希望这样做的方式如下所示:

  • 如果字符串为空,则失败
  • 如果它以一个
    *
    开头,那么做一些事情,以某种方式解析左边的子树,并在一个步骤中获得列表的其余部分,然后从剩余部分中解析右边的子树,形成一个
    分支
  • 如果它是另一个字符,则制作一个
无需找出拆分字符串的位置,实际拆分字符串,然后解析一半;只要解析列表,直到你不能再解析了,然后剩下的(或者我应该说是对的?)就可以再次解析了

因此:定义一个函数
constructTrie'::String->Maybe(Trie,String)
,该函数将
字符串的开头消耗为
Trie
,然后保留未解析的位(如果解析失败,则不提供任何内容)。此函数将是递归的,这就是它获得额外输出值的原因:它需要额外的管道来移动列表的其余部分
constructTrie
本身可以定义为其周围的包装:

-- Maybe Trie because it's perfectly possible that the String just won't parse
constructTrie :: String -> Maybe Trie
constructTrie s = do (t, "") <- constructTrie' s
                  -- patmat failure in a monad calls fail; fail @Maybe _ = Nothing
                     return t

-- can make this local to constructTrie in a where clause
-- or leave it exposed in case it's useful
constructTrie' :: String -> Maybe (Trie, String)
constructTrie' "" = Nothing -- can't parse something from nothing!
constructTrie' ('*':leaves) = do (ln, rs) <- constructTrie' leaves
                              -- Parse out left branch and leave the right part
                              -- untouched. Doesn't copy the left half
                                 (rn, rest) <- constructTrie' rs
                              -- Parse out the right branch. Since, when parsing
                              -- "**ABC", the recursion will end up with
                              -- constructTrie' "*ABC", we should allow the slop.
                                 return (Branch ln rn, rest)
constructTrie' (x:xs) = return (Leaf x, xs)
--可能是Trie,因为字符串很可能无法解析
constructTrie::String->Maybe Trie

constructrie s=do(t,“”)这是一种很好的方法。我们甚至可以更进一步,使用
StateT-String-Maybe-Trie
来避免传递字符串状态。这是一种很好的方法。我们甚至可以更进一步,使用
StateT-String-Maybe-Trie
来避免传递字符串状态。