Vòng lặp trong lập trình chức năng không được thực hiện với báo cáo kiểm soát như for
và while
, nó được thực hiện với các cuộc gọi rõ ràng để các chức năng như map
, fold
hoặc đệ quy - tất cả đều có liên quan đến việc đặt vòng lặp gọi nội bên trong chức năng khác . Nếu mã vòng lặp làm thay đổi các biến bên ngoài vòng lặp, hàm vòng lặp bên trong này sẽ thao tác các biến bên ngoài phạm vi của nó và do đó sẽ không trong sạch . Vì vậy, toàn bộ chức năng bên ngoài là thuần túy, nhưng vòng lặp thì không. Cấu trúc vòng lặp trong lập trình chức năng yêu cầu bạn làm cho trạng thái rõ ràng. Dịch mã của bạn sang một cái gì đó bằng cách sử dụng các công cụ lặp lập trình chức năng cho thấy tạp chất:
int as_int(char *str)
{
int acc = 0; /* accumulate the partial result */
map(takeWhile(isdigit, str), void function(char *chr) {
acc = acc * 10 + (chr - '0');
});
return acc;
}
(Lưu ý - cú pháp này là gần đúng để có được ý tưởng chung)
Mã này sử dụng một hàm bên trong cho thân vòng lặp phải biến đổi biến acc
nằm ngoài phạm vi của nó. Điều này là không tinh khiết - chức năng vòng lặp bên trong phụ thuộc vào bối cảnh vòng lặp bên ngoài , gọi nó nhiều lần với cùng một ký tự sẽ có tác dụng phụ và thứ tự bạn gọi nó trong chuỗi các ký tự là vấn đề. Trong lập trình chức năng, để biến điều này thành một hàm thuần túy, bạn sẽ phải làm cho sự phụ thuộc này vào trạng thái được chuyển giữa các lần lặp lặp rõ ràng với fold
:
int as_int(char *str)
{
return fold(takeWhile(isdigit, str), 0, int function(char *chr, int acc) {
return acc * 10 + (chr - '0');
});
}
fold
sử dụng chức năng của hai đối số cho thân vòng lặp bên trong: đối số thứ nhất là một mục trong chuỗi fold
được lặp lại, trong khi đối số thứ hai là một giá trị mà thân vòng lặp bên trong sử dụng để xây dựng kết quả một phần. Đối với lần lặp vòng lặp thứ nhất, acc
là 0, đối với lần thứ hai, acc
là bất cứ điều gì mà lệnh gọi hàm vòng lặp thứ nhất được trả về, đối với vòng thứ ba, đó là bất cứ vòng lặp thứ hai nào được trả về và vòng lặp cuối cùng trả về kết quả của toàn bộ fold
biểu thức.
Lưu ý rằng đây thực sự không phải là vấn đề với mã của bạn từ góc độ của phần còn lại của chương trình - cả hai định nghĩa as_int
đều thuần túy. Sự khác biệt là bằng cách biến mã vòng lặp bên trong thành một hàm thuần túy, bạn có thể tận dụng hàng loạt công cụ mà lập trình chức năng cung cấp để phân tách vòng lặp thành một thứ gì đó mang tính khai báo hơn (ví dụ: sử dụng TakeWhile, gập, lọc, ánh xạ, v.v.)