【问题标题】:Real World Haskell Chapter 3 excercise: Binary Tree with 1 value constructor - follow up真实世界 Haskell 第 3 章练习:具有 1 个值构造函数的二叉树 - 跟进
【发布时间】:2019-12-12 21:15:31
【问题描述】:

这个问题不是重复的

A question with the same title already exists,但在我看来,answer 只是部分解决了这个问题,我也对它没有回答的问题感兴趣。

前言

Real World Haskell 在第 3 章第 58 页提出了以下二叉树数据类型的定义,

data Tree a = Node a (Tree a) (Tree a)
            | Empty
              deriving (Show)

它提供了两个构造函数(用于空和非空Trees)。

另一方面,在第 60 页,一个练习挑战读者使用单个构造函数定义 Tree 数据类型。

经过多次尝试,我想出了与上面链接的解决方案相同的解决方案:

data Tree a = Node a (Maybe (Tree a)) (Maybe (Tree a)) deriving(Show)

链接问题中未回答的问题

这个定义的缺点是它不允许实例化一个空的Tree,尽管它允许通过以下语法实例化一个带有空子代的Tree

Node 3 Nothing (Just (Node 2 Nothing Nothing))

我认为没有比上述更好的解决方案了,如果没有“独立”的空树是可以接受的,并且要求是只使用一个构造函数。

对上述陈述发表一些评论会很好;但是,我的主要问题是如何使用一个构造函数定义Tree,以便实例化一个空的Tree

既然我已经写了这个问题,我认为一个可能的答案是以下,我完全不确定:

如果一个子节点是否为空,无论它是通过Nothing 还是Just (Node ...) 构建的,对于整个树(或根节点)来说几乎相同,它确实可以自己定义作为NothingJust (Node ...);也就是说,只有一个构造函数,Nothing 是实例化一棵空树的方法。 (换句话说,我刚刚开始认为这个问题本质上是“格式错误的”。尽管如此,我还是会发布它,因为我认为我可以从您的 cmets/answers 中学到一些东西。)

上面说的有道理吗?

一个可能的答案

原始问题中的评论提出了以下解决方案

data Tree a = Tree (Maybe (a,Tree a,Tree a))

(我的理解)允许通过Node Nothing 实例化一个空树,或者通过Node (Just (value,child1,child2)) 实例化一个非空树。

【问题讨论】:

  • data Tree a = Tree (Maybe (a,Tree a,Tree a)) 似乎在原始定义中指定 NothingEmptyJustNode。它到底有什么好处..?

标签: haskell tree maybe


【解决方案1】:

这里有个提示:您可以使用 n 元组类型将任何 n 元构造函数转换为 1 元构造函数。

例如,您的树类型与以下树类型同构:

data Tree a = Node (a, Tree a, Tree a)
            | Empty

我认为您现在应该能够将这种类型转换为只涉及一个构造函数的类型。

【讨论】:

  • 我认为您指的是我刚刚包含在答案中的解决方案。就算有效,我也觉得有点“笨拙”。
  • @EnricoMariaDeAngelis 啊,对。我错过了。它有什么笨拙的地方?我认为没有其他简单的方法。从类型理论的角度来看,标准树定义是Tree a = 1 + (a * Tree a * Tree a),其中+ 表示求和类型,* 表示乘积类型,1 表示单元类型。在 Haskell 中,转换为 Tree a = Either () (a, Tree a, Tree a)Either () 最好写成 Maybe
  • 我的类型理论水平相当低(如果不是零的话),所以我可能会在未来某个时候回到你的这个评论。
  • 但是,如果你能澄清最后一部分,那就太好了:Either ()最好写成Maybe;我的理解是 MaybeEither () 都是类型 ctor,它们采用 1 个具体类型 a 来生成包裹在 something 中的 a 类型的值,或者 somethingelse i>,其中 somethingJust 代表 MaybeRight 代表 EithersomethingelseNothing 代表 MaybeLeft ()Either ()。所以它们在我看来是两种不同的东西(即使它们可以编码相同的信息)。
  • @EnricoMariaDeAngelis 你写的是正确的。它们是两种不同的类型,但它们编码相同的信息。在类型论中,我们说它们是同构的,因为有两个函数 f :: Maybe a -> Either () ag :: Either () a -> Maybe a 是互逆的。在很多情况下,由于这个原因,我们并没有真正区分这两者。在实践中,在 Haskell 中使用 Either () a 是不寻常的,因为 Maybe a 可以做同样的工作并且在概念上更容易理解。从某种意义上说,这只是品味问题。
【解决方案2】:

@chi 和他的 cmets 的回答说明了一切,可以通过以下方式完成:

data Tree a = T (Either () (a, Tree a, Tree a)) deriving Show

树的一个例​​子是:

node1 = T $ Right ("data node 1", node2, node3)
node2 = T $ Left ()
node3 = T $ Right ("data node 3", node2, node2)

  $> node1
T (Right ("data node 1",T (Left ()),T (Right ("data node 3",T (Left ()),T (Left ())))))

不过大家也已经说了,那可以换成Maybe,因为Either ()可以看成Maybe a

【讨论】:

  • 你为什么要发布一个只是重申其他人所说的话的答案?
  • @chepner 在答案中总结和浓缩所有内容
  • 谢谢,这对我有帮助。
猜你喜欢
  • 2011-06-03
  • 2020-04-09
  • 2017-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多