Phần lớn này theo sau http://www.haskell.org/haskellwiki/Memoization.
Bạn muốn có chức năng loại (a -> b). Nếu nó không tự gọi, thì bạn chỉ có thể viết một trình bao bọc đơn giản để lưu trữ các giá trị trả về. cách tốt nhất để lưu trữ ánh xạ này phụ thuộc vào thuộc tính nào của bạn có thể khai thác . Đặt hàng là khá nhiều tối thiểu. Với số nguyên , bạn có thể tạo danh sách lười vô hạn hoặc cây giữ các giá trị.
type Cacher a b = (a -> b) -> a -> b
positive_list_cacher :: Cacher Int b
positive_list_cacher f n = (map f [0..]) !! n
hoặc
integer_list_cacher :: Cacher Int b
integer_list_cacher f n = (map f (interleave [0..] [-1, -2, ..]) !!
index n where
index n | n < 0 = 2*abs(n) - 1
index n | n >= 0 = 2 * n
Vì vậy, giả sử nó là đệ quy. Sau đó, bạn cần nó để gọi không chính nó, nhưng phiên bản memoized, vì vậy bạn vượt qua rằng trong thay vì:
f_with_memo :: (a -> b) -> a -> b
f_with_memo memoed base = base_answer
f_with_memo memoed arg = calc (memoed (simpler arg))
Phiên bản memoized là, tất nhiên, những gì chúng tôi đang cố gắng để xác định.
Nhưng chúng ta có thể bắt đầu bằng cách tạo ra một chức năng lưu trữ nguyên liệu đầu vào của nó:
Chúng ta có thể xây dựng một mức độ bằng cách đi qua trong một chức năng mà tạo ra một cấu trúc rằng lưu trữ giá trị. . Ngoại trừ chúng ta cần phải tạo ra các phiên bản của f rằng đã có chức năng lưu trữ thông qua vào
Nhờ sự lười biếng, đây là không có vấn đề:
memoize cacher f = cached where
cached = cacher (f cached)
sau đó tất cả chúng ta cần là để sử dụng nó:
exposed_f = memoize cacher_for_f f
bài viết này cung cấp cho những gợi ý như thế nào để sử dụng một lựa chọn kiểu lớp trên đầu vào cho các chức năng để làm các việc trên, thay vì chọn mộtrõ ràngchức năng bộ nhớ đệm. Điều này có thể thực sự tốt đẹp - thay vì rõ ràng xây dựng bộ nhớ cache cho từng kết hợp loại đầu vào, chúng tôi hoàn toàn có thể kết hợp các bộ đệm a và b vào bộ đệm cho một hàm lấy a và b.
Thông báo cuối cùng: sử dụng kỹ thuật lười biếng này có nghĩa là bộ nhớ cache không bao giờ co lại, chỉ phát triển. Thay vào đó, nếu bạn sử dụng trình đơn IO, bạn có thể quản lý điều này, nhưng làm điều đó một cách khôn ngoan phụ thuộc vào các mẫu sử dụng.
Tôi khó có thể đánh vần Haskell :), nhưng tôi không nghĩ vậy. Bản ghi nhớ liên quan đến chính xác loại trạng thái tĩnh mà ngôn ngữ chức năng thuần túy không cho phép, khi tôi hiểu chúng. Tất nhiên, sử dụng một đơn nguyên sẽ làm cho điều này khả thi, tôi nghĩ. Nhưng loại phần thứ hai của bạn chỉ ra rằng bạn đã biết điều đó rồi. –
@Mike: Tôi có thể đã nghĩ điều tương tự, nhưng thực tế các ngôn ngữ chức năng có thể thực hiện ghi nhớ tốt, như câu trả lời hiển thị. Họ chỉ phải vượt qua trạng thái xung quanh thông qua các tham số hàm. – LarsH