Temel do blok sözdizimi için açıklamaya ihtiyacınız var
Ghci'de şunu yazdım:
let x = do
i <- [1..5]
j <- [2..4]
return i
Beklenen Sonuç:
[1,2,3,4,5]
Gerçek sonuç:
[1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]
Bu çıktının arkasındaki mantığı anlamıyorum. Sanırım nedeni monad ile ilgili bir şey olabilir, ancak işlevsel programlamada çok yeniyim, keşke birinin bunu biraz açıklayabilmesini isterdim.
Eşdeğer formu Liste-anlama'da da denedim ve sonuç aynı, bu da burada yanlış anladığım temel bir şey olduğu anlamına geliyor.
Yanıtlar
Eşdeğer formu Liste-anlama'da da denedim ve sonuç aynı
İyi bir fikir. Öyle olur ki, listeler için dogösterim, liste anlamalarıyla tamamen aynıdır. (Aslında, herhangi bir monad için notasyonu kullanabileceğiniz gibi, herhangi bir monad için liste-anlama notasyonunu kullanmanıza izin veren sözdizimsel bir uzantı vardır do.)
Yani, neden yerine [a | a<-[0,1], b<-[2,3]]verir diye soruyorsunuz . Bunun şaşırtıcı görünme şekli, liste anlamalarını matematikte bulacağınız gibi küme anlamaları olarak düşünmenizdir . Haskellers genellikle listeleri setler için geçici bir stand-in olarak kullansa da listeler set değildir. Listelerin anlamaları, belirli bir anlama olarak hareket ederse[0,0,1,1][0,1]
[x | x <- [0,1,0]]
aynı zamanda sadece [0,1]sonucu olarak vermelidir (veya en azından verdiği ile aynı sonucu vermelidir [x|x<-[0,1]]).
Genel olarak, bu tür ayıklama çiftleri, eşitlik kontrolleri gerektirir ve eğer bunu verimli hale getirmek istiyorsanız, aynı zamanda bir sıralama veya bir hashing yöntemi. Listeler böyle bir şey yapmaz, bu nedenle set benzeri bir davranış istiyorsanız, set uygulama veri yapısı kullanmalısınız. Setve HashSeten yaygın olanlarıdır.
Bunun nedeni, do mekanizmasının (neyse ki) en içteki kodun aslında döngü değişkenlerine (bazılarına) atıfta bulunup bulunmadığına aldırış etmemesidir.
En içteki koddan bağımsız olarak her zaman 3 * 5 = 15 değer elde ettiğinizi görün:
λ>
λ> xs1 = do { i <- [1..5] ; j <- [2..4] ; return i }
λ> xs1
[1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]
λ>
λ> xs2 = do { i <- [1..5] ; j <- [2..4] ; return 9 }
λ> xs2
[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9]
λ>
λ> xs3 = do { i <- [1..5] ; j <- [2..4] ; return (i,j) }
λ> xs3
[(1,2),(1,3),(1,4),(2,2),(2,3),(2,4),(3,2),(3,3),(3,4),(4,2),(4,3),(4,4),(5,2),(5,3),(5,4)]
λ>
λ> length xs1
15
λ> length xs2
15
λ> length xs3
15
λ>
Anladığım kadarıyla, bu Haskell'in C, C ++, Fortran, Python ile paylaştığı mükemmel standart bir davranış ...
C ++ eşdeğeri bir örnek:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> vi{1,2,3,4,5};
std::vector<int> vj{2,3,4};
for (int i: vi)
for (int j: vj)
std::cout << i << ", ";
std::cout << std::endl;
return EXIT_SUCCESS;
}
C ++ çıktı:
$ ./a.out 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, $