微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Haskell 列表理解 - 并非所有数据都被传输

如何解决Haskell 列表理解 - 并非所有数据都被传输

我有这样的网络数据结构:

data Network = Empty | Node Double [Network] [Network]

其中 Double 代表节点标签,第一个列表是父节点,第二个列表是给定节点的子节点。假设所有边都是从根到叶的,并且没有循环。

我有一个这样的边缘数据结构:

data Edge = Edge (Network,Network)

边从 a->b 指向 Edge (a,b)

我编写了一个函数,用于列出网络的所有树边。为了进一步定义这一点,具有多个父节点(网状节点)的节点的所有父(传入)边都不是树边。我正在考虑来自网状节点的输出边以及网络中的所有其他边是树边。

我尝试像这样使用列表理解来完成这个任务:

getTreeEdges :: Network -> [Edge]
getTreeEdges (Node label ps cs) = nub (getTreeEdgesHelp (Node label (Empty:[]) cs))
getTreeEdgesHelp :: Network -> [Edge]
--leaf node case,children is empty list
getTreeEdgesHelp n@(Node _ ps []) = [Edge (p,n) | p <- ps ]
--reticulation node and root case,there is more than one parent or parent is empty(root)
getTreeEdgesHelp (Node _ ps cs) | ((length ps) > 1||ps==(Empty:[])) = (concat (map getTreeEdgesHelp cs))
--interal node case
getTreeEdgesHelp n@(Node _ ps cs) = ([Edge (p,n) | p <- ps ])++( concat (map getTreeEdgesHelp cs))

如您所见,列表推导式用于存储叶子和内部边的父边,而根节点和网状节点则跳过向列表添加边并进行递归。叶结束递归。

我遇到的问题是存储的边不包含所有预期信息。更具体地说,父节点的父信息消失了。其他信息仍然存在,标签和子项不受影响。

例如,假设我存储边 (a,b)。网络 b 存储完全正确。网络 a 有它自己(根节点)和所有后代节点都存在并正确标记,但它们都没有其父节点的任何条目,每个节点的父节点都是 []

这里是一个给定的输入、输出和预期输出的示例,具有 newick 格式 (a,b)c,用于具有子节点 a 和 b 的节点 c。我还在标签后的方括号中包含给定节点的父节点。为了全面披露,以下是我为 ShowNetwork 定义 Edge 的方式。

instance Show Network where
  show Empty = "_"
  show (Node a ps []) = (show a)++"["++printlabels ps++"]"
  show (Node a ps [x,y]) = "("++show x++","++show y ++ ")"++(show a)++"["++printlabels ps++"]"
  show (Node a ps [x]) = "("++show x++")"++(show a)++"["++printlabels ps++"]"
printlabels :: [Network] -> [Char]
printlabels [] = " "
printlabels (Empty:_) = "root"
printlabels ((Node label _ _):ns) = (show label)++","++(printlabels ns)

这是我生成的示例树。因为标签比较长,我用字母代替了内部节点的标签,用整数代替了叶子的标签

(((4.0[c],((0.0[f])f[e,h],(1.0[g],2.0[g])g[e])e[c])c[h],(0.0[f])f[e,h])h[d],3.0[d])d[root]

是下图的表示。

The example Network with non tree edges marked in red and the example edge being queried in green

运行上述函数给出:

[(d,h),(h,c),(c,4.0),e),(f,0.0),(e,g),(g,1.0),2.0),(d,3.0)]

instance Show Edge where
  show ( Edge ((Node labelu _ _),(Node labelv _ _)) ) = "("++(show labelu)++","++(show labelv)++")"

当我查询单个边时,说出位置 5 (e,g) 处的边,然后将 Show 重写为 Edge

instance Show Edge where
  show ( Edge (u,v) ) = "("++(show u)++"=1,2="++(show v)++")"

我得到 (((1.0[ ],2.0[ ])g[ ],0.0[ ])e[ ]=1,2=(1.0[g],2.0[g])g[e]) 而预期的结果是 (((1.0[g],2.0[g])g[e],h])e[c]=1,2.0[g])g[e])

我注意到的另一个错误0.0 被指定为 g 的兄弟,这是不正确的。正如评论者指出的那样,我在尝试获取树边时没有更改任何节点,我只是将节点分配给适当的边对并将其存储在列表中。您还可以看到我输入的网络具有正确的出身和结构。

这里会发生什么?我是 Haskell 的新手,我使用列表理解错误吗?

解决方法

对于纯语言而言,您的数据结构非常不寻常,并且将被证明非常难以使用。尽管您表示的图形是非循环的,但您用来表示它的数据结构是循环的:父节点的子节点又是节点。这意味着当你修改某个东西时,你需要循环修改它:如果我改变一个节点,我也必须改变相应的孩子的父级,以及它的每个子级的父级等等。这是非常复杂和微妙的。

这个挑战是纯语言独有的:改变循环数据结构对于可变数据结构来说不是问题——你可以只在一个地方改变它,它被引用的任何地方都可以“看到”改变。

最好是找到图形的非循环表示。例如:图是边的列表。如果您需要它,您还可以包含一组节点(因此可以表示度数为 0 的节点)。仅通过标签引用节点,当您需要有关它们的信息时,请在列表中查找它们。

另一种方法是inductive graph (在 fgl 库中实现)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?