ต้องการคำอธิบายสำหรับไวยากรณ์การบล็อกขั้นพื้นฐาน
ใน 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 แต่ฉันยังใหม่มากกับการเขียนโปรแกรมเชิงฟังก์ชันฉันหวังว่าจะมีใครอธิบายได้สักหน่อย
ฉันยังได้ลองใช้รูปแบบความเท่าเทียมกันในความเข้าใจรายการและผลลัพธ์ก็เหมือนกันซึ่งหมายความว่ามีบางอย่างพื้นฐานที่ฉันเข้าใจผิดที่นี่
คำตอบ
ฉันยังได้ลองใช้รูปแบบความเท่าเทียมกันในรายการความเข้าใจและผลลัพธ์ก็เหมือนกัน
ความคิดที่ดี. ดังนั้นสำหรับรายการ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พบบ่อยที่สุด
เนื่องจากกลไก 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, $