2009-11-21 10 views
7

यह एक स्पष्ट रूप से निराशाजनक मामला जैसा प्रतीत हो सकता है, लेकिन क्या पर्ल में अपरिवर्तनीय वस्तुओं का चक्रीय ग्राफ बनाने के लिए एक चाल है? कुछ इस तरह:मैं पर्ल और मूस में अपरिवर्तनीय वस्तुओं का चक्रीय ग्राफ कैसे बना सकता हूं?

package Node; 
use Moose; 
has [qw/parent child/] => (is => 'ro', isa => 'Node'); 

package main; 
my $a = Node->new; 
my $b = Node->new(parent => $a); 

अब अगर मैं $b को इंगित करने के $a->child चाहता था, मैं क्या कर सकता है?

+1

शायद एक बेवकूफ सवाल है, लेकिन अपरिवर्तनीयता क्यों मायने रखती है? – Ether

+1

मेरे लिए यह 'नोड' ऑब्जेक्ट्स के बारे में कारण बनाना आसान बनाता है। अन्य कारणों से 'अपरिवर्तनीयता' टैग देखें। – zoul

उत्तर

4

मुझे जाना था कि वास्तव में अपरिवर्तनीय भाषाएं जैसी कुछ कैसे करती हैं, और मुझे लगता है कि निम्नलिखित संभवतः एक उचित प्रयास है।

use 5.10.0; 
{ 

    package Node; 
    use Moose; 
    has [qw(parent child)] => (isa => 'Node', is => 'ro'); 

    sub BUILD { 
     my ($self, $p) = @_; 
     return unless exists $p->{_child}; 
     my $child = Node->new(parent => $self, %{ delete $p->{_child} },); 
     $self->meta->get_attribute('child')->set_value($self, $child); 
    } 
} 

say Node->new(_child => {})->dump 

मूल रूप से बजाय वस्तुओं को अलग से बनाने की कोशिश की, तो आप है माता पिता ऑटो फिर जीवित करना यह तर्क में गुजर के आधार पर बच्चे। इसके लिए आउटपुट है, जो मुझे विश्वास है कि आप जिस संरचना को चाहते थे।

$VAR1 = bless({ 
       'child' => bless({ 
            'parent' => $VAR1 
            }, 'Node') 
       }, 'Node'); 
+1

अपरिवर्तनीय और चक्रीय ऑक्सीमोरोन है। इस तरह से अपरिवर्तनीय भाषाएं इसका सामना करती हैं। उदाहरण के लिए एर्लांग में आप कोई चक्रीय डेटा संरचना नहीं बना सकते हैं। अपरिवर्तनीयता को शामिल करना तरीका है कि चक्रों को कैसे रोकें और यही कारण है कि अपरिवर्तनीयता शामिल है। –

+1

एक counterexample के लिए, देखें http://www.haskell.org/haskellwiki/Tying_the_Knot –

1

मैं अभी भी मूस के लिए बहुत नया हूं, लेकिन क्या ट्रिगर काम करेगा?

use Modern::Perl; 

package Node; 
use Moose; 
has 'parent' => (
    is => 'ro', 
    isa => 'Node', 
    trigger => sub{ 
     my ($self, $parent) = @_; 
     $parent->{child} = $self unless defined $parent->child; 
    } 
); 

has 'child' => (
    is => 'ro', 
    isa => 'Node', 
    trigger => sub{ 
     my ($self, $child) = @_; 
     $child->{parent} = $self unless defined $child->parent; 
    } 
); 

package main; 
my $p = Node->new; 
my $c = Node->new(parent => $p); 

say $p, ' == ', $c->parent; 
say $c, ' == ', $p->child; 
+0

यह आपके मूस ऑब्जेक्ट को हैशरफ के रूप में इलाज करने के लिए धोखा दे रहा है। यह आज एक हो सकता है, लेकिन इस बात की कोई गारंटी नहीं है कि यह कल होगा। –

5

आप आलसी आरंभीकरण के साथ खेल खेलने सकता है:

BEGIN { 
    for (qw/ parent child /) { 
    no strict 'refs'; 

    my $squirreled = "_" . $_; 

    *{"_build" . $squirreled} = sub { 
     my($self) = @_; 
     my $proto = $self->$squirreled; 
     ref $proto eq "REF" ? $$proto : $proto; 
    }; 

    *{"has" . $squirreled} = sub { 
     my($self) = @_; 
     defined $self->$squirreled; 
    }; 
    } 
} 

यह

my $a = Node->new(parent => \my $b, name => "A"); 
    $b = Node->new(child =>  $a, name => "B"); 

for ($a, $b) { 
    print $_->name, ":\n"; 
    if ($_->has_parent) { 
    print " - parent: ", $_->parent->name, "\n"; 
    } 
    elsif ($_->has_child) { 
    print " - child: ", $_->child->name, "\n"; 
    } 
} 

इसका उत्पादन होता है की अनुमति देता है:

package Node; 
use Moose; 

has parent => (
    is => 'ro', 
    isa => 'Node', 
    lazy => 1, 
    init_arg => undef, 
    builder => '_build_parent', 
); 

has _parent => (
    is => 'ro', 
    init_arg => 'parent', 
); 

has child => (
    is => 'ro', 
    isa => 'Node', 
    lazy => 1, 
    init_arg => undef, 
    builder => '_build_child', 
); 

has _child => (
    is => 'ro', 
    init_arg => 'child', 
    predicate => undef, 
); 

has name => is => 'ro', isa => 'Str'; 

बिल्डरों और मक्खी पर विधेय उत्पन्न

A: 
    - parent: B 
B: 
    - child: A 

कोड η-conversion‎ के साथ और अधिक सुंदर हो सकता है, लेकिन मूस बिल्डर तरीकों के पैरामीटर पास नहीं होंगे।

संबंधित मुद्दे