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
Algorithm 如何在Haskell中表示两棵树之间的映射?_Algorithm_Haskell_Tree_Mapping_Abstract Syntax Tree - Fatal编程技术网

Algorithm 如何在Haskell中表示两棵树之间的映射?

Algorithm 如何在Haskell中表示两棵树之间的映射?,algorithm,haskell,tree,mapping,abstract-syntax-tree,Algorithm,Haskell,Tree,Mapping,Abstract Syntax Tree,我正试图在Haskell中实现一个树处理算法(由于这是我的第一个Haskell程序!),我正在努力设计数据结构。有哪位FP大师能帮忙吗 我将从描述算法的重要特征开始,勾勒出我将如何使用命令式语言来实现这一点,并以我在Haskell中迄今为止所做的跌跌撞撞的小步骤结束 问题 我不会详细描述完整的算法,但要点如下: data AnnotatedTree = Tree Int addIndex :: Int -> AnnotatedTree -> (AnnotatedTree, Int)

我正试图在Haskell中实现一个树处理算法(由于这是我的第一个Haskell程序!),我正在努力设计数据结构。有哪位FP大师能帮忙吗

我将从描述算法的重要特征开始,勾勒出我将如何使用命令式语言来实现这一点,并以我在Haskell中迄今为止所做的跌跌撞撞的小步骤结束

问题 我不会详细描述完整的算法,但要点如下:

data AnnotatedTree = Tree Int

addIndex :: Int -> AnnotatedTree -> (AnnotatedTree, Int)

indexedTree = addIndex 0 tree
  • 该算法在两棵玫瑰树X和Y上运行
  • 算法的第一阶段根据每个节点及其子节点的标签和属性,计算每个节点的一些派生属性
  • 这些派生属性用于计算两棵树之间的部分映射,因此X中的节点可能与Y中的节点关联,反之亦然。由于映射是局部的,因此可以映射X或Y中的任何节点(即,在另一棵树中有一个伙伴),或者可以取消映射
  • 算法的最后阶段通过检查映射节点的父节点/子节点/兄弟节点的一系列操作来优化这些映射
因此,数据结构必须具有以下特征:

  • 给定对节点的引用,提供对该节点的父节点、该节点的兄弟节点以及该节点的子节点的访问
  • 给定输入树中的节点,允许使用附加信息(派生属性和对另一棵树中节点的可选引用)对该节点进行注释
紧急解决方案的草图 如果我使用命令式语言实现这个算法,那么解决方案如下所示

假设起点是输入树的以下定义:

struct node {
    // Identifier for this node, unique within the containing tree
    size_t id;

    // Label of this node
    enum label label;

    // Attributes of this node
    // An attribute can be assumed to be a key-value pair
    // Details of the attributes themselves aren't material to this
    // discussion, so the "attribute" type is left opaque
    struct attribute **attributes;
    size_t n_attributes;

    // Pointer to parent of this node
    // NULL iff this node is root
    struct node *parent;

    // Pointer to first child of this node
    // NULL iff this node is leaf
    struct node *child;

    // Double-linked list of siblings of this node
    struct node *prev;
    struct node *next;
};
data Tree = Leaf Label Attributes
          | Node Label Attributes [Tree]
嵌入在每个节点中的指针显然支持算法所需的上/下/左/右遍历

可以通过定义以下结构来实现注释:

struct algo_node {
    // Pointer to input node which has been wrapped
    struct node *node;

    // Derived properties computed by first phase of the algorithm
    // Details of the properties themselves aren't material to this
    // discussion, so the "derived" type is left opaque
    struct derived props;

    // Pointer to corresponding node in the other tree
    // NULL iff this node is unmatched
    struct node *match;
};
算法的第一阶段为每个输入树中的每个
节点
构造一个
算法节点

算法节点
节点
的映射非常简单:遵循嵌入的
*节点
指针。通过将
algou节点
s存储在一个数组中,由输入节点的
id
索引,可以支持另一个方向的映射

当然,这只是一种可能的实现。有许多变化是可能的,包括

  • 列表
    队列
    接口后面抽象子链表,而不是存储三个原始指针
  • 不要通过索引将输入树与算法树相关联,而是直接在
    struct algou_节点中编码父/子/同级关系
搬到哈斯克尔 让我们从输入树的以下定义开始:

struct node {
    // Identifier for this node, unique within the containing tree
    size_t id;

    // Label of this node
    enum label label;

    // Attributes of this node
    // An attribute can be assumed to be a key-value pair
    // Details of the attributes themselves aren't material to this
    // discussion, so the "attribute" type is left opaque
    struct attribute **attributes;
    size_t n_attributes;

    // Pointer to parent of this node
    // NULL iff this node is root
    struct node *parent;

    // Pointer to first child of this node
    // NULL iff this node is leaf
    struct node *child;

    // Double-linked list of siblings of this node
    struct node *prev;
    struct node *next;
};
data Tree = Leaf Label Attributes
          | Node Label Attributes [Tree]
可以通过以下方式实现每个节点的id扩充:

data AnnotatedTree = Tree Int

addIndex :: Int -> AnnotatedTree -> (AnnotatedTree, Int)

indexedTree = addIndex 0 tree
类似地,我们可以编写一个计算派生属性的函数:

data AnnotatedTree = Tree DerivedProperties

computeDerived :: DerivedProperties -> AnnotatedTree -> (AnnotatedTree, DerivedProperties)

derivedTree = computeDerived DefaultDerived tree
上面的代码片段可以通过少量的工作进行调整,这样
AnnotatedTree
就同时包含索引和派生属性

但是,我不知道从何处开始表示这两棵树之间的映射。根据一些阅读,我有一些不成熟的想法

  • 定义
    AnnotatedTree
    以包含从另一棵树的根到映射节点的路径-编码为每个连续子列表的索引列表,
    [Integer]
    • 使用拉链(我目前对拉链的理解相当松散)通过路径访问映射的节点(或其父节点/子节点/兄弟节点)
    • 或者用一个镜头(我对它的理解更不清楚!)来做同样的事情
  • 定义
    AnnotatedTree
    以直接包含对映射节点的引用,作为
    可能树
    • 但是,我看不到一种方法可以走到映射节点的父节点/同级节点
。。。但我真的需要一些指导,这些指导(如果有的话)是值得追求的


任何帮助都将不胜感激

您可以使用
Int
id标记树节点,并使用拉链(使用
Data.tree
Data.tree.Zipper
是个好主意,因为无需重新发明轮子)。然后,可以使用
Data.IntMap
将辅助属性附加到节点,以将节点id映射到所需的任何对象。特别是,您可以创建一个
IntMap
来从节点id映射到该节点的
TreePos Full Int
,以便可以查看该节点的父节点、同级节点和子节点

如果
x
中的一个节点
x
y
中有一个对应的节点
y
,那么
y
中与
x
的后代对应的所有节点都是
y
的后代吗?@danidiaz否,不一定。我认为拉链确实是您在这里想要的。是否值得将我的数据转换为data.Tree以便我可以使用data.Tree.Zipper?还是我应该自己拉拉链?这两条路线上都有我应该知道的陷阱吗?