Có nhiều danh sách/loại bộ sưu tập khác nhau trong F #.
Loại F # list
. Như Chris đã nói, bạn không thể khởi tạo giá trị đệ quy của kiểu này, vì kiểu không lười và không thể thay đổi được (Tính không thay đổi có nghĩa là bạn phải tạo nó cùng một lúc và thực tế là không lười biếng có nghĩa là bạn không thể sử dụng đệ quy F # giá trị sử dụng let rec
). Như ssp đã nói, bạn có thể sử dụng Reflection để hack nó, nhưng đó có thể là một trường hợp mà chúng ta không muốn thảo luận.
Loại khác là seq
(thực tế là IEnumerable
) hoặc loại LazyList
từ PowerPack. Đây là những lười biếng, vì vậy bạn có thể sử dụng let rec
để tạo ra một giá trị tuần hoàn. Tuy nhiên, (theo như tôi biết), không có hàm nào làm việc với chúng đưa danh sách tuần hoàn vào tài khoản - nếu bạn tạo danh sách tuần hoàn, điều đó có nghĩa là bạn đang tạo một danh sách vô hạn, do đó kết quả của (ví dụ) map
sẽ là danh sách vô hạn tiềm ẩn.
Dưới đây là một ví dụ cho LazyList
loại:
#r "FSharp.PowerPack.dll"
// Valid use of value recursion
let rec ones = LazyList.consDelayed 1 (fun() -> ones)
Seq.take 5 l // Gives [1; 1; 1; 1; 1]
Câu hỏi đặt ra là những loại dữ liệu bạn có thể xác định chính mình.Chris hiển thị danh sách có thể thay đổi và nếu bạn viết các hoạt động sửa đổi nó, chúng sẽ ảnh hưởng đến toàn bộ danh sách (nếu bạn diễn giải nó dưới dạng cấu trúc dữ liệu vô hạn). Bạn cũng có thể định nghĩa một kiểu dữ liệu lười biếng (potentionally cyclic) và thực hiện các thao tác xử lý chu kỳ, vì vậy khi bạn tạo một danh sách tuần hoàn và đưa nó vào danh sách khác, nó sẽ tạo ra danh sách tuần hoàn (chứ không phải là một potentionally) cấu trúc dữ liệu vô hạn).
Việc kê khai loại có thể giống như thế này (tôi đang sử dụng loại đối tượng, để chúng ta có thể sử dụng bình đẳng tham khảo khi kiểm tra chu kỳ):
type CyclicListValue<'a> =
Nil | Cons of 'a * Lazy<CyclicList<'a>>
and CyclicList<'a>(value:CyclicListValue<'a>) =
member x.Value = value
Chức năng sau map
xử lý chu kỳ - nếu bạn cho nó một danh sách theo chu kỳ, nó sẽ trả về một danh sách mới được tạo ra với cùng một cấu trúc cyclic:
let map f (cl:CyclicList<_>) =
// 'start' is the first element of the list (used for cycle checking)
// 'l' is the list we're processing
// 'lazyRes' is a function that returns the first cell of the resulting list
// (which is not available on the first call, but can be accessed
// later, because the list is constructed lazily)
let rec mapAux start (l:CyclicList<_>) lazyRes =
match l.Value with
| Nil -> new CyclicList<_>(Nil)
| Cons(v, rest) when rest.Value = start -> lazyRes()
| Cons(v, rest) ->
let value = Cons(f v, lazy mapAux start rest.Value lazyRes)
new CyclicList<_>(value)
let rec res = mapAux cl cl (fun() -> res)
res
Nguồn
2010-02-18 18:52:09
Cảm ơn :) (5 thêm những gì bạn xác thực ngu ngốc!) – leppie
Có thể đáng nói đến là điều này có thể được thực hiện trong OCaml. Tôi thậm chí có thể trích dẫn các ứng dụng thực tế duy nhất của khả năng này trong việc thực hiện đóng cửa đệ quy ở đây: http://www.ffconsultancy.com/ocaml/benefits/interpreter.html –