Mở rộng biểu thức danh sách (List Comprehensions)
Haskell cung cấp một số phần mở rộng ngôn ngữ để tăng cường khả năng của biểu thức danh sách, giúp viết mã ngắn gọn và gần với truy vấn SQL.
ParallelListComp
Phần mở rộng
ParallelListComp cho phép kết hợp các luồng sinh giá trị song song bằng cách sử dụng ký hiệu
| thay vì lồng nhau. Điều này tương đương với việc dùng
zip giữa các danh sách được tạo độc lập.
Prelude> :set -XParallelListComp
Prelude> [(a,b,c,d) | a <- [1..3], b <- [2..4] | c <- [3..5], d <- [4..6]]
[(1,2,3,4),(1,3,3,5),(1,4,3,6),(2,2,4,4),(2,3,4,5),(2,4,4,6),(3,2,5,4),(3,3,5,5),(3,4,5,6)]
Mỗi cặp biến ở hai phía của dấu
| được ghép theo vị trí, giống như hành vi của
zip.
TransformListComp
Phần mở rộng
TransformListComp bổ sung cú pháp mới vào biểu thức danh sách:
then,
group,
by, và
using. Nhờ đó, người dùng có thể áp dụng các phép biến đổi như sắp xếp hoặc nhóm phần tử ngay trong biểu thức.
Prelude> :set -XTransformListComp
Prelude> :m +GHC.Exts
Prelude GHC.Exts> [(i,j) | i <- [1..3], j <- [2..4], then reverse]
[(3,4),(3,3),(3,2),(2,4),(2,3),(2,2),(1,4),(1,3),(1,2)]
Prelude GHC.Exts> [(i,j) | i <- [1..3], j <- [2..4], then sortWith by (i+j)]
[(1,2),(1,3),(2,2),(1,4),(2,3),(3,2),(2,4),(3,3),(3,4)]
Prelude GHC.Exts> [(sum vals, vals) | i <- [1..3], j <- [2..4], let vals = [(i,j)], then group by (i+j) using groupWith]
[(3,[(1,2)]),(4,[(1,3),(2,2)]),(5,[(1,4),(2,3),(3,2)]),(6,[(2,4),(3,3)]),(7,[(3,4)])]
Cú pháp
then f by e cho phép chỉ định hàm biến đổi
f và khóa
e để sắp xếp hoặc nhóm. Hàm
groupWith từ
GHC.Exts thường được dùng cùng với
group by ... using.
Ví dụ khác sử dụng
inits từ
Data.List:
Prelude GHC.Exts Data.List> [x | x <- [1..3], then group using inits]
[[],[1],[1,2],[1,2,3]]
MonadComprehensions
Khi bật cả
MonadComprehensions và
TransformListComp, biểu thức danh sách có thể hoạt động trên bất kỳ monad nào, không chỉ là danh sách. Điều này cho phép viết các biểu thức kiểu danh sách trong ngữ cảnh
Maybe,
IO, v.v.
{-# LANGUAGE MonadComprehensions, TransformListComp #-}
pairs :: [(String, Int)]
pairs = [("a", 1), ("b", 2), ("c", 3)]
example = [ (x, y)
| x <- lookup "a" pairs
, y <- lookup "b" pairs
, then (\f -> case f of
v | v == 2 -> Just (x, y)
_ -> Nothing)
by (x * y)
]
-- Kết quả: Just (1,2)
Trong ví dụ trên,
lookup trả về
Maybe Int, và toàn bộ biểu thức được đánh giá trong ngữ cảnh monad
Maybe. Phần mở rộng
then ... by vẫn hoạt động nhờ hỗ trợ từ
TransformListComp.