Pertanyaan Apa perbedaan konteks dalam peta bertingkat dan tidak bersarang di Perl 6?


Saya memiliki sedikit kode ini. Yang pertama, tidak bersarang map menghasilkan beberapa barang, dan yang bersarang tidak. Saya pikir saya mengerti mengapa yang kedua tidak berhasil. Ini adalah urutan malas dan Perl 6 mengumpulkan hasil. Tidak apa-apa. Tapi bukan yang pertama (tidak bersarang) map malas dengan cara yang sama? Bagaimana cara menghasilkan apa pun jika saya tidak melakukan apa pun dengan hasil peta? Artinya, bagaimana cara orang pertama malas? Apakah secara otomatis mendapatkan konteks sink di mana saya harus secara eksplisit menyediakan sink (atau sesuatu) ke yang bersarang? Entah bagaimana saya pikir Perl 6 harus bisa memikirkan hal ini untuk saya.

my @array = (1, 2), (3, 4), ('a', 'b');

say "---On its own:";
my @item = 1, 2, 3;
@item.map: {
    say $_;
    };

say "---Inside another map:";
@array.map: {
    my @item = 1, 2, 3;
    @item.map: {
        say $_;
        }
    };

Inilah hasilnya:

---On its own:
1
2
3
---Inside another map:

Ini terkait dengan pertanyaan itu Bagaimana saya bisa menggunakan "peta" di dalam "untuk" loop di Perl 6?. Yang mengatakan apa yang harus dilakukan, tetapi saya meminta lebih dari a Mengapa pertanyaan.

Dalam hal itu, solusinya adalah menambahkan eager, sink, atau tugas ke interior map:

say "---eager:";
@array.map: {
    my @item = 1, 2, 3;
    eager @item.map: {
        say $_;
        }
    };

say "---sink:";
@array.map: {
    my @item = 1, 2, 3;
    sink @item.map: {
        say $_;
        }
    };

say "---assignment:";
@array.map: {
    my @item = 1, 2, 3;
    @ = @item.map: {
        say $_;
        }
    };

4
2018-01-17 11:59


asal


Jawaban:


Isi dari setiap file program, blok, subrutin, dll adalah "daftar pernyataan" yang terdiri dari titik koma yang dipisahkan1 pernyataan. Dengan itu dalam pikiran:

  1. Pernyataan yang didapat hangus:

    • Semua kecuali pernyataan final dalam daftar pernyataan.
    • Setiap pernyataan lingkaran (for, while, dll.2) di tingkat daftar pernyataan3, bahkan ketika itu yang terakhir.
    • Pernyataan apa pun dalam daftar pernyataan tingkat teratas dari suatu program atau file modul, bahkan ketika itu adalah yang terakhir.4
  2. Pernyataan yang didapat dikembalikan bukannya tenggelam:

    • Pernyataan akhir dalam daftar pernyataan, kecuali untuk kasus-kasus yang disebutkan di atas.

Menenggelamkan kekuatan evaluasi, kembali tidak.

Contoh

Dalam kasus Anda, yang pertama map pernyataan ada di tengah daftar pernyataan, sehingga mendapat hangus.

Tapi bersarang map Pernyataan adalah pernyataan akhir dari daftar pernyataannya, sehingga hasilnya mendapat dikembalikan dalam bentuk belum-iterasi Seq.

Orang tuanya map Pernyataan juga merupakan pernyataan akhir, tetapi ada di daftar pernyataan tingkat atas dari file program, sehingga mendapat hangus, menyebabkannya dengan penuh semangat mengiterasi urutan yang terdiri dari tiga Seq nilai-nilai. (Masukkan a say pernyataan sebelum batin map, untuk melihat ini.)
Tetapi tidak ada yang tenggelam, atau sebaliknya, masing-masing dari ketiga batin itu Seq nilai-nilai.

Dari dokumen desain

Lebih verbosely, dari Sinopsis 04, baris 664:

Di setiap urutan pernyataan, hanya nilai dari pernyataan akhir yang dikembalikan, jadi semua pernyataan sebelumnya dievaluasi dalam konteks sink, yang secara otomatis bersemangat, untuk memaksa evaluasi efek samping. (Efek samping adalah satu-satunya alasan untuk mengeksekusi pernyataan seperti itu di tempat pertama, dan Perl akan, pada kenyataannya, memperingatkan Anda jika Anda melakukan sesuatu yang "tidak berguna" dalam konteks wastafel.) Lingkaran dalam konteks wastafel tidak hanya mengevaluasi dirinya sendiri dengan penuh semangat, tetapi dapat mengoptimalkan produksi dari setiap nilai dari loop.

Pernyataan akhir dari daftar pernyataan bukanlah konteks wastafel, dan dapat mengembalikan nilai apa pun termasuk daftar yang malas. Namun, untuk mendukung harapan pemrogram imperatif (sebagian besar dari kita, ternyata), setiap loop eksplisit yang ditemukan sebagai pernyataan akhir dari daftar pernyataan secara otomatis dipaksa untuk menggunakan sink semantik sehingga loop selesai hingga selesai sebelum kembali dari blok.

Konteks wastafel yang dipaksakan ini diterapkan ke loop hanya pada tingkat daftar pernyataan, yaitu, pada tingkat atas unit kompilasi, atau langsung di dalam blok. Membangun yang mengurai pernyataan tunggal atau semilist sebagai argumen yang diduga ingin hasil pernyataan itu, sehingga konstruksi seperti itu tetap malas bahkan ketika pernyataan itu adalah loop.


1) Ketika penjepit penutup } muncul sebagai token yang tepat terakhir dari garis, seperti pada
my @a = @b.map: { $_ + 1 } # whitespace/comment doesn't count
itu juga mengakhiri pernyataan saat ini, tetapi sebaliknya titik koma diperlukan untuk memisahkan pernyataan.

2) map tidak dihitung, karena itu adalah fungsi dan bukan kata kunci loop.

3) Berarti bahwa ketika pernyataan loop muncul di tempat yang berbeda daripada secara langsung dalam daftar pernyataan, mis.
lazy for ^10 { .say } # as argument to a keyword expecting a single statement
(for ^10 { .say }) # inside an expression
maka tidak tenggelam secara default. Itulah paragraf terakhir dari kutipan sinopsis yang coba dikatakan.

UPDATE: Ini tampaknya tidak benar-benar terjadi di Rakudo, tapi itu mungkin bug.

4) Aturan ini tidak disebutkan dalam sinopsis, tetapi cara kerjanya di Rakudo, dan saya cukup yakin itu disengaja.


8
2018-01-17 12:33



.map pada dasarnya mengembalikan .Seq. Apa yang terjadi adalah peta batin mengembalikan Seq ke peta luar, tetapi karena hasil peta itu tenggelam, mereka menghilang tanpa diulangi.

Jika Anda mengatakan peta luar, Anda akan menarik hasil peta dalam, dan Anda akan melihat hasil dari .Seq peta batin kembali:

my @array = (1, 2), (3, 4), ('a', 'b');
say "---Inside another map:";
say @array.map: {
    my @item = 1, 2, 3;
    @item.map: {
        say $_;
        }
    }
---Inside another map:
1
2
3
1
2
3
1
2
3
((True True True) (True True True) (True True True))

Harapan itu masuk akal :-)

Solusi alternatif adalah dengan menambahkan nilai kembali spesifik ke peta luar. Maka peta batin akan tenggelam, dan karena itu iterasi, seperti:

my @array = (1, 2), (3, 4), ('a', 'b');
say "---Inside another map:";
say @array.map: {
    my @item = 1, 2, 3;
    @item.map: {
        say $_;
        }
    42   # make sure ^^ map is sunk
    }
---Inside another map:
1
2
3
1
2
3
1
2
3

5
2018-01-17 12:35