Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
没有数据的Haskell显示树。树或派生(显示)_Haskell - Fatal编程技术网

没有数据的Haskell显示树。树或派生(显示)

没有数据的Haskell显示树。树或派生(显示),haskell,Haskell,大家好,我的实例在Haskell中显示一棵树时遇到了问题:下面是我的代码: data Tree a b = Branch b (Tree a b) (Tree a b) | Leaf a instance (Show a, Show b) =>Show (Tree a b) where show (Leaf x) = " "++show x ++"\n" show (Branch val l r) = show val ++ "\n" ++" " ++ show l

大家好,我的实例在Haskell中显示一棵树时遇到了问题:下面是我的代码:

data Tree a b = Branch b (Tree a b) (Tree a b)
          | Leaf a
instance  (Show a, Show b) =>Show (Tree a b) where
show (Leaf x) = " "++show x ++"\n"
show (Branch val l r) = show val ++ "\n" ++" " ++ show l ++ " " ++ show r
这是我的测试用例和输出,它是错误的:

 Branch "<" (Branch "<" (Leaf 'a') (Leaf 'c')) (Branch "<" (Leaf 'g') (Branch     "<" (Leaf 'n') (Leaf 'y'))))
 "<"
  "<"
    'a'
    'c'
  "<"
    'g'
  "<"
    'n'
    'y'
正确的输出

 "<"
  "<"
    'a'
    'c'
  "<"
    'g'
    "<"
      'n'
      'y'

任何帮助都会很好

显示函数无法知道每行缩进的深度。为子树预加一个空格将不起作用,因为它们通常有多行

您需要定义一个以缩进为参数的辅助函数:

indent n x = concat (replicate n " ") ++ show x ++ "\n"

f n (Leaf x) = indent n x
f n (Branch val l r) = indent n val ++ f (n+1) l ++ f (n+1) r

instance (Show a, Show b) => Show (Tree a b) where
  show tree = f 0 tree

显示函数无法知道每行缩进的深度。为子树预加一个空格将不起作用,因为它们通常有多行

您需要定义一个以缩进为参数的辅助函数:

indent n x = concat (replicate n " ") ++ show x ++ "\n"

f n (Leaf x) = indent n x
f n (Branch val l r) = indent n val ++ f (n+1) l ++ f (n+1) r

instance (Show a, Show b) => Show (Tree a b) where
  show tree = f 0 tree

考虑以下几点:

putStrLn ("First line" ++ "   " ++ "\n" ++ "Second line")
输出是

First line   
Second line

因为换行符不保留缩进。您需要找到一种方法来显示您要打印的每个项目所需缩进的大小。

考虑以下几点:

putStrLn ("First line" ++ "   " ++ "\n" ++ "Second line")
输出是

First line   
Second line
因为换行符不保留缩进。你需要找到一种方法来显示你想要打印出来的每一项需要多大的缩进。

注意:这篇文章是用识字的Haskell写的。将其复制到您喜爱的编辑器中,另存为Tree.lhs或类似文件,然后加载到GHCi中

让我们试试另一种方法。我们创建字符串的行,而不是将树显示为单个字符串:

> data Tree a b = Branch b (Tree a b) (Tree a b) | Leaf a

> instance (Show a, Show b) => Show (Tree a b) where
>   show tree = magic (go tree)
>      where
>        go :: (Show a, Show b) => Tree a b -> [String]
现在还不用担心魔法,它的类型将是magic::[String]->String。 让我们专注于先走。如果要显示单个叶,只需关注单个值:

>        go (Leaf v)       = [show v]
现在是关于树枝和它们的缩进。我们仍然可以在叶子的情况下显示该值:

但是我们必须确保实际的分支前面有正确数量的空格。我们使用一个名为indent的尚未定义的函数:

现在我们已经准备好了几乎所有的东西:如果indent按照它的名字做,它将把go l++go r返回的[String]中的所有字符串缩进一个空格。因此,树的分支在前面总是有一个空间作为根本身。现在缺少的只是缩进和魔法:

那相当容易。当然,您可以将“”:与其他内容交换

现在魔术的工作是把所有的绳子粘在一起。由于要将整棵树缩进一个空格,所以我们最后一次使用缩进:

>        magic = unlines . indent
就这样。以下是完整的代码,以便更好地进行概述:

instance (Show a, Show b) => Show (Tree a b) where
  show tree = magic (go tree)
    where
      go (Leaf v)       = [show v]
      go (Branch v l r) = show v : indent (go l ++ go r)
      indent            = map (' ':)
      magic             = unlines . indent
这项技术的好处在于,我们永远不必使用显式级别或声明某个地方的空间数。我们可以在树上走一走,创建我们的[String],然后让magic和indent为我们完成剩下的工作。

注意:这篇文章是用识字的Haskell写的。将其复制到您喜爱的编辑器中,另存为Tree.lhs或类似文件,然后加载到GHCi中

让我们试试另一种方法。我们创建字符串的行,而不是将树显示为单个字符串:

> data Tree a b = Branch b (Tree a b) (Tree a b) | Leaf a

> instance (Show a, Show b) => Show (Tree a b) where
>   show tree = magic (go tree)
>      where
>        go :: (Show a, Show b) => Tree a b -> [String]
现在还不用担心魔法,它的类型将是magic::[String]->String。 让我们专注于先走。如果要显示单个叶,只需关注单个值:

>        go (Leaf v)       = [show v]
现在是关于树枝和它们的缩进。我们仍然可以在叶子的情况下显示该值:

但是我们必须确保实际的分支前面有正确数量的空格。我们使用一个名为indent的尚未定义的函数:

现在我们已经准备好了几乎所有的东西:如果indent按照它的名字做,它将把go l++go r返回的[String]中的所有字符串缩进一个空格。因此,树的分支在前面总是有一个空间作为根本身。现在缺少的只是缩进和魔法:

那相当容易。当然,您可以将“”:与其他内容交换

现在魔术的工作是把所有的绳子粘在一起。由于要将整棵树缩进一个空格,所以我们最后一次使用缩进:

>        magic = unlines . indent
就这样。以下是完整的代码,以便更好地进行概述:

instance (Show a, Show b) => Show (Tree a b) where
  show tree = magic (go tree)
    where
      go (Leaf v)       = [show v]
      go (Branch v l r) = show v : indent (go l ++ go r)
      indent            = map (' ':)
      magic             = unlines . indent
这项技术的好处在于,我们永远不必使用显式级别或声明某个地方的空间数。我们可以在树上走一走,创建我们的[String],然后让magic和indent为我们完成其余的工作。

您的树类型让我有点恼火,因为它是monad,但不能是monad。让我通过翻转类型参数来解决这个问题:

data Tree b a = Branch b (Tree a b) (Tree a b)
              | Leaf a

display' :: (Show a, Show b) => String -> Tree b a -> String -> String
display' prefix (Leaf a) =
  (prefix ++) . shows a . ('\n' :)
display' prefix (Branch v l r) =
  (prefix ++) . shows v . ('\n' :) . display' prefix' l . display' prefix' r
  where prefix' = ' ' : prefix

display :: (Show a, Show b) => Tree b a -> String
display t = display' ' ' t ""
你的树型让我有点恼火,因为它是单子,但不能是单子。让我通过翻转类型参数来解决这个问题:

data Tree b a = Branch b (Tree a b) (Tree a b)
              | Leaf a

display' :: (Show a, Show b) => String -> Tree b a -> String -> String
display' prefix (Leaf a) =
  (prefix ++) . shows a . ('\n' :)
display' prefix (Branch v l r) =
  (prefix ++) . shows v . ('\n' :) . display' prefix' l . display' prefix' r
  where prefix' = ' ' : prefix

display :: (Show a, Show b) => Tree b a -> String
display t = display' ' ' t ""

等待这真的编译了吗?您缺少显示行的缩进。您明确表示不使用数据。Tree表明您已经了解drawTree。我可以理解为什么在构建自己的解决方案时,您可能希望避免查看drawTree的源代码:对于

自己创造想法的乐趣。我不明白的是,为什么你会向其他地方寻求解决方案。从StackOverflow上的某个随机人那里学习想法比从containers package的作者那里学习想法更好吗?这实际上不是一个很好的展示实例。通常,您应该能够复制show的结果,并将其用作Haskell源代码,可能还添加了类型注释。作为一个独立的showTree函数,这会更好。等等。这真的编译了吗?您缺少显示行的缩进。您明确表示不使用数据。Tree表明您已经了解drawTree。我可以理解为什么在构建自己的解决方案时,您可能希望避免查看drawTree的来源:为了自己创造想法的乐趣。我不明白的是,为什么你会向其他地方寻求解决方案。从StackOverflow上的某个随机人那里学习想法比从containers package的作者那里学习想法更好吗?这实际上不是一个很好的展示实例。通常,您应该能够复制show的结果,并将其用作Haskell源代码,可能还添加了类型注释。作为一个独立的showTree函数,这会更好。谢谢你,伙计,这是正确的。我不知道如何将缩进作为一个参数,这里发生了一些奇怪的事情。首先,concat replicate n是replicate n。是的,但很容易改为2空间缩进,或者--[,或其他。不管怎样,重要的是:它能有效地回答问题吗?聪明往往比清晰容易…谢谢,伙计,这是正确的。我不知道如何将缩进作为一个参数。这里发生了一些奇怪的事情。例如,concat replicate n就是replicate n。是的,但很容易改变nge到2空间缩进,或--[,或其他。无论如何,重要的是:它能有效地回答问题吗?聪明往往比清晰容易…对于那些等待另一首诗的人来说:不。我这周有一首诗,但没有那么好/因此我没有心情/很快再写一首。下一首诗可能下周三,取决于问题ns。目前实现的这种技术的缺点是映射调用堆栈。在这个特定的应用程序中,这很好,但一般来说,这种模式是需要注意的,以避免严重的性能问题。我注意到base-4.7.0.1中inits的实现与参考实现基本相同在Haskell 98报告中的上,我做了类似的事情,这让我发现它的速度非常慢。新的实现在速度上相当复杂,但有一种简单的方法可以通过计数来完成。我认为,通过传递缩进字符串,在递归调用中为其添加空格,可以在不进行计数的情况下解决问题。@dfeur我想到了类似的事情,但我没有时间检查它;我将在周日尝试测试/评测这两种变体,目前无法访问PC。对于那些等待另一首诗的人:不。我本周有一首诗,但没有那么好/因此我没有心情/很快写另一首诗。下一首诗可能下周三,根据问题的不同。目前实现的这种技术的缺点是map调用stack up。在这个特定的应用程序中,这很好,但一般来说,这种模式是需要注意的,以避免严重的性能问题。我注意到base-4.7.0.1中inits的实现基本上与tHaskell 98报告中的参考实现也做了类似的事情,这让我发现它的速度非常慢。新的实现在速度上相当复杂,但有一种简单的方法可以通过计数来完成。我认为,通过传递缩进字符串,在e递归调用。@dfeur我想到了类似的东西,但我没有时间检查它;将在星期天和基准测试/配置两种变体上进行尝试,目前无法访问PC。