Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.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
Data structures F#纯功能数据结构权重偏差LeftIstHeap ex 3.4_Data Structures_F#_Functional Programming_Purely Functional_Tailrecursion Modulo Cons - Fatal编程技术网

Data structures F#纯功能数据结构权重偏差LeftIstHeap ex 3.4

Data structures F#纯功能数据结构权重偏差LeftIstHeap ex 3.4,data-structures,f#,functional-programming,purely-functional,tailrecursion-modulo-cons,Data Structures,F#,Functional Programming,Purely Functional,Tailrecursion Modulo Cons,我正在研究冈崎的纯功能数据结构,并试图构建事物的F#实现。我还将完成书中列出的练习(有些练习很有挑战性)。我一直在练习3.4中,它要求修改WeightBiasedLeftistHeap的merge函数,使其在一个过程中执行,而不是原来的两个过程实现 我还没有弄明白如何做到这一点,并希望得到一些建议。还有一个例子,一个家伙在SML中通过几乎内联makeT函数来实现这一点。我开始走这条路线(在评论的第3.4节第一次尝试中)。但放弃了这种方法,因为我认为这真的不是在一个过程中执行的(它仍然会“直到到达

我正在研究冈崎的纯功能数据结构,并试图构建事物的F#实现。我还将完成书中列出的练习(有些练习很有挑战性)。我一直在练习3.4中,它要求修改WeightBiasedLeftistHeap的merge函数,使其在一个过程中执行,而不是原来的两个过程实现

我还没有弄明白如何做到这一点,并希望得到一些建议。还有一个例子,一个家伙在SML中通过几乎内联makeT函数来实现这一点。我开始走这条路线(在评论的第3.4节第一次尝试中)。但放弃了这种方法,因为我认为这真的不是在一个过程中执行的(它仍然会“直到到达一片叶子,然后展开并重建树)。我将其解释为仍然是两个过程的合并是错误的吗

以下是我在F#中失败的尝试:

类型堆
模块权重biasedleftistheap=
异常清空异常
让重量h=
匹配h
|E->0
|T(w,w,w)->w
让我们做一个b=
让weightA=weightA
让weightB=weightB
如果weightA>=weightB,则
T(权重a+权重b+1,x,a,b)
其他的
T(权重a+权重b+1,x,b,a)
//练习3.4第一次尝试
//让rec合并3\u 4 l r=
//将l,r与
//| l,E->l
//| E,r->r
//| T(u,lx,la,lb)作为左侧,(T(u,rx,ra,rb)作为右侧)->
//如果lx=权重b,则
//T(权重A+权重B+1,lx,la,右)
//否则
//T(权重A+权重B+1,lx,右侧,la)
//否则
//让右侧=合并3_4左侧rb
//设weightA=weightRa
//让weightB=正确的重量
//
//如果weightA>=weightB,则
//T(权重A+权重B+1,rx,ra,右侧)
//否则
//T(权重A+权重B+1,rx,右侧,ra)
//练习3.4秒尝试(失败!)
//这不管用,我想不出如何在一次传球中做到这一点
让我们合并3\u 4 l r=
让rec合并'l r值leftChild=
将l,r与
|l,E->市场价值左子l
|E,r->市场价值leftChild r
|T(x,lx,la,lb)作为左侧,(T(x,rx,ra,rb)作为右侧)->
如果lx市场(rx、ra、h))
将l,r与
|l,E->l
|E,r->r
|T(x,lx,la,lb)作为左侧,(T(x,rx,ra,rb)作为右侧)->
让lf=funh->makeT(lx,la,h)
如果lx市场(rx、ra、h))
让rec合并lr=
将l,r与
|l,E->l
|E,r->r
|T(x,lx,la,lb)作为左侧,(T(x,rx,ra,rb)作为右侧)->

如果lx我不确定我是否正确理解了这个问题,但这是我的尝试-目前,
merge
操作执行对
merge
(这是第一次)的递归调用,当它到达堆的末尾时(在
match
中的前两种情况),它将新构造的堆返回给调用者,并调用
makeT
几次(这是第二次)

我不认为简单的内联
mMakeT
是我们被要求做的事情(如果是,只需将
inline
添加到
makeT
中,这样做不会降低代码的可读性:-)

但是,可以做的是修改
merge
函数以使用延续传递样式,其中“剩余工作”作为函数传递给递归调用(因此在第一次传递完成后,堆栈上没有待完成的工作)。可以这样做:

let rec merge' l r cont =
    match l,r with
    | l,E -> cont l // Return result by calling  the continuation
    | E,r -> cont r // (same here)
    | T(_, lx, la, lb) as lh, (T(_, rx, ra, rb) as rh) ->
        if lx <= rx then
            // Perform recursive call and give it 'makeT' as a continuation
            merge' lb rh (makeT lx la)
        else
            // (same here)
            merge' lh rb (makeT rx ra)

// Using 'id' as a continuation, we just return the 
// resulting heap after it is constructed
let merge l r = merge' l r id
let rec merge'l r cont=
将l,r与
|l,E->cont l//通过调用continuation返回结果
|E,r->cont r//(此处相同)
|T(x,lx,la,lb)作为左侧,(T(x,rx,ra,rb)作为右侧)->

如果lx第一个问题是:什么构成“一次通过”算法?可以自然地实现为一个自顶向下的循环的东西是合格的。相比之下,递归(天真地编译)通常有两个过程,一个在向下,一个在向上。尾部递归可以很容易地编译成循环,并且通常是函数式语言。是一种类似的优化,尽管不太常见。但是,即使您的编译器不支持尾部递归模cons,您也可以轻松地手动将此类实现转换为循环

尾部递归模cons与普通尾部递归类似,不同之处在于尾部调用被包装在构造函数中,构造函数可以在递归调用之前进行分配和部分填充。在本例中,您希望返回表达式类似于
T(1+size(a)+size(b)+size(c),x,a,merge(b,c))
。此处所需的关键洞察(如上的编辑中所述)是,您不需要执行合并来了解结果的大小,从而知道新树的哪一侧应该继续。这是因为
merge(b,c)
的大小总是
size(b)+size(c)
,可以在合并之外计算

请注意,普通左边堆的原始
rank
函数不共享此属性,因此无法以这种方式进行优化

基本上,然后将这两个调用内联到makeT中,并将形式为
size(merge(b,c))
的调用转换为
size(b)+size(c)

进行此更改后,生成的函数会比原始函数慢很多,因为它可以在计算递归合并之前返回结果的根

类似地,在涉及锁和变异的并发环境中,新的实现可以支持
let rec merge' l r cont =
    match l,r with
    | l,E -> cont l // Return result by calling  the continuation
    | E,r -> cont r // (same here)
    | T(_, lx, la, lb) as lh, (T(_, rx, ra, rb) as rh) ->
        if lx <= rx then
            // Perform recursive call and give it 'makeT' as a continuation
            merge' lb rh (makeT lx la)
        else
            // (same here)
            merge' lh rb (makeT rx ra)

// Using 'id' as a continuation, we just return the 
// resulting heap after it is constructed
let merge l r = merge' l r id