递归子程序

时间:2018-11-06 22:12:28

标签: perl6 raku rakudo

比方说,我有一组软件包a,b,c,...,每个软件包都有名称,版本和依赖项。

在下面的代码中, get-cand 子获取一个程序包,并从池中返回候选对象(以及它们的依赖关系递归)。

因此,如果它使用名为 c 的软件包,并且该池具有

包c1: 名称 c ,版本 1 ,部门 a (任何版本)和 b (版本 1

包c2: 名称 c ,版本 2 ,部门 b (版本2)

它将返回以下数据结构:

((c1 ((((a1 ()) (a2 ()))) (((b1 ()))))) (c2 ((((b2 ()))))))  # can't figure out how to get rid of empty lists here

我正在尝试编写将采用上述数据结构的 select-cand 子程序,目标是返回不冲突的第一个候选对象(与已安装的软件包),然后递归检查它也是依赖项。

所以子应该像这样工作:

  • 检查 c1 ,如果冲突返回False,请使用 c1 并下降到单位
  • (现在位于c1部门)检查 a1 ,如果冲突返回True,则检查下一个候选对象( a2

最终,如果成功运行,它应该返回[c1 a2 b1]或[c2 b2],如果所有候选者都冲突,则不返回任何内容。

但此刻 select-cand 子返回:[c1 a1 a2 c2 b2]这是错误的,因为我只需要c1(递归dep)或c2。

conflicts 是一个占位符子,目前仅出于测试目的而排除b1软件包)

#!/usr/bin/env perl6

my %pkgs;

class Pkg {
  has         $.name;
  has Version $.version = Version.new;
    has Pkg     @.dep;

    method Str {
      $!name ~ $!version;
    }
}

my $a1 = Pkg.new: name => 'a', version => Version.new: <1>;
my $a2 = Pkg.new: name => 'a', version => Version.new: <2>;
my $b1 = Pkg.new: name => 'b', version => Version.new: <1>;
my $b2 = Pkg.new: name => 'b', version => Version.new: <2>;
my $c1 = Pkg.new: name => 'c', version => Version.new: <1>;
my $c2 = Pkg.new: name => 'c', version => Version.new: <2>;

$c1.dep.push: Pkg.new(name => 'a');
$c1.dep.push: Pkg.new(name => 'b', version => Version.new: <1>);

$c2.dep.push: Pkg.new(name => 'b', version => Version.new: <2>);

%pkgs<a> .push: $a1, $a2;
%pkgs<b> .push: $b1, $b2;
%pkgs<c> .push: $c1, $c2;


sub return-pkg (Pkg $pkg) {
  my @pkgs = flat %pkgs{$pkg.name};
    return grep {$_.version ~~ $pkg.version}, @pkgs;
}  

sub get-cand (Pkg $pkg) {
    gather {
        take return-pkg($pkg).map( -> $pkg {
            ($pkg, $pkg.dep.map( -> $pkg {
                get-cand($pkg).Slip
            }).Slip)
        }).cache;
    }
}

sub conflicts (Pkg $pkg) {
  return True if $pkg.name eq <a> and $pkg.version eq <1>; 
  #take $pkg.Str if $pkg.name eq <a> and $pkg.version eq <1>; 
}

multi select-cand (Pkg $pkg) {
  return $pkg.Str if not conflicts $pkg;
}

multi select-cand (@cand) {
  gather {
    @cand.map({ .first({ take select-cand $_ })});
    }
}

my $c = Pkg.new: name => 'c';

my @cand =  get-cand $c;
my @selected = select-cand @cand;

say @selected; # [(c1 () (a2) (b1))]

0 个答案:

没有答案