ต้องการคำอธิบายสำหรับไวยากรณ์การบล็อกขั้นพื้นฐาน

Aug 19 2020

ใน ghci ฉันเขียนว่า:

 let x = do
    i <- [1..5]
    j <- [2..4]
    return i 

ผลลัพธ์ที่คาดหวัง:

[1,2,3,4,5]

ผลลัพธ์จริง:

[1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]

ฉันไม่เข้าใจตรรกะเบื้องหลังผลลัพธ์นั้น ฉันคิดว่าเหตุผลอาจเป็นเรื่องเกี่ยวกับ monad แต่ฉันยังใหม่มากกับการเขียนโปรแกรมเชิงฟังก์ชันฉันหวังว่าจะมีใครอธิบายได้สักหน่อย

ฉันยังได้ลองใช้รูปแบบความเท่าเทียมกันในความเข้าใจรายการและผลลัพธ์ก็เหมือนกันซึ่งหมายความว่ามีบางอย่างพื้นฐานที่ฉันเข้าใจผิดที่นี่

คำตอบ

5 leftaroundabout Aug 19 2020 at 13:08

ฉันยังได้ลองใช้รูปแบบความเท่าเทียมกันในรายการความเข้าใจและผลลัพธ์ก็เหมือนกัน

ความคิดที่ดี. ดังนั้นสำหรับรายการdoสัญกรณ์จะเหมือนกับการเข้าใจรายการทุกประการ (ในความเป็นจริงมีส่วนขยายทางวากยสัมพันธ์ที่ช่วยให้คุณใช้สัญกรณ์ความเข้าใจรายการสำหรับ monad ใด ๆ เช่นคุณสามารถใช้doสัญกรณ์สำหรับ monad ใด ๆ ก็ได้)

ดังนั้นคุณจะถามว่าทำไม[a | a<-[0,1], b<-[2,3]]ให้แทน[0,0,1,1] [0,1]วิธีนี้ดูน่าแปลกใจคือถ้าคุณคิดเกี่ยวกับความเข้าใจในรายการเป็นความเข้าใจที่ตั้งไว้เช่นเดียวกับที่คุณพบในวิชาคณิตศาสตร์ แต่รายการไม่ได้ตั้งค่าแม้ว่า Haskellers มักใช้รายการเป็นตัวสำรองชั่วคราวสำหรับชุด หากรายการความเข้าใจทำหน้าที่เป็นชุดความเข้าใจแล้ว

  [x | x <- [0,1,0]]

นอกจากนี้ยังควรให้ผลผลิตเพียง[0,1]เป็นผลของมัน (หรืออย่างน้อยก็ควรผลผลิตเดียวกันผลเป็น[x|x<-[0,1]]ไม่)

โดยทั่วไปการกำจัดวัชพืชที่ซ้ำกันประเภทนี้จำเป็นต้องมีการตรวจสอบความเท่าเทียมกันและหากคุณต้องการทำให้มีประสิทธิภาพด้วยไม่ว่าจะเป็นการสั่งซื้อหรือวิธีการแฮช รายการจะไม่ทำสิ่งนั้นดังนั้นหากคุณต้องการพฤติกรรมที่เหมือนเซ็ตคุณควรใช้โครงสร้างข้อมูลที่ใช้การตั้งค่า SetและHashSetพบบ่อยที่สุด

6 jpmarinier Aug 19 2020 at 12:54

เนื่องจากกลไก do ไม่สนใจ (โชคดี) ว่าโค้ดด้านในสุดอ้างถึงตัวแปรลูป (บางส่วน) จริงหรือไม่

คุณจะได้รับ 3 * 5 = 15 ค่าเสมอโดยไม่คำนึงถึงรหัสด้านในสุด:

 λ> 
 λ> 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
 λ> 

เท่าที่ฉันสามารถบอกได้นี่เป็นพฤติกรรมมาตรฐานที่สมบูรณ์แบบที่ Haskell แบ่งปันกับ C, C ++, Fortran, Python ...

ตัวอย่างที่เทียบเท่า C ++:

#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 ++:

$ ./a.out 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, $