This one is not from the F# List module but from the
Seq one.
F# sequences are logical series of elements all of one type. They can be converted into lists.
F# sequences are 'lazy', and can be infinite, the elements are computed only as required.
As LISP list can't be infinite, the argument function which generates each sequence element needs to have break loop condition which returns nil.
Seq.
unfold;; gc:unfold
;; Returns a list that contains the elements generated by the given computation.
;; The given initial state argument is passed to the element generator.
;; For each list elements in the stream are generated on-demand by applying the element generator,
;; until a nil value is returned by the element generator.
;; Each call to the element generator returns a new residual state.
;; The generator have to return a dotted pair (or a list) or nil to break the loop.
;; The pair 'car' is a new result to add to the list and 'cdr' the new state.
;;
;; Signature: ('State -> ('T . 'State)) -> 'State -> 'T list
(defun gc:unfold (fun state / res lst)
(setq fun (eval fun))
(reverse
(while (setq res (fun state))
(setq state (cdr res)
lst (cons (car res) lst)
)
)
)
)
Examples:
Binary codes lower than 300
_$ (gc:unfold '(lambda (x) (if (< x 300) (cons x (* 2 x)))) 1)
(1 2 4 8 16 32 64 128 256)
The break condition of the generator function is: state < 300.
The state is succesively passed as argument to the generator which returns a dotted pair: (result . modified_state)
1 -> (1 . 2)
2 -> (2 . 4)
4 -> (4 . 8)
8 -> (8 . 16)
...
256 -> (256 . 512)
512 -> nil
Fibonacci sequence
(defun fib (p)
(if (< (cdr p) 1000)
(cons (cdr p) (cons (cdr p) (+ (car p) (cdr p))))
)
)
(gc:unfold 'fib '(1 . 1))
Returns (1 2 3 5 8 13 21 34 55 89 144 233 377 610 987)
In this case, as the initial state is a dotted pair, each element returned by the generator will be a 'dotted list':
(fib '(1 . 1) -> (1 1 . 2)
(fib '(1 . 2) -> (2 2 . 3)
(fib '(2 . 3) -> (3 3 . 5)
(fib '(3 . 5) -> (5 5 . 8)
...
(fib '(610 . 987)) -> (987 987 . 1597)
(fib '(987 . 1597)) -> nil
A different way for a Fibonacci sequence in a defun function using a counter value as break condition:
(defun fibonacci (len)
(gc:unfold
'(lambda (x)
(if (< (caddr x) len)
(list (cadr x) (cadr x) (+ (car x) (cadr x)) (1+ (caddr x)))
)
)
'(1 1 0)
)
)
(fibonacci 5) returns (1 2 3 5 8)
Here, the state is a list which first item is the result to add to the return list, the second is to be used with the first to generate the next result and state, the third is the counter.
The lambda function (generator) returns succesively:
'(1 1 0) -> (1 1 2 1)
'(1 2 1) -> (2 2 3 2)
'(2 3 2) -> (3 3 5 3)
'(3 5 3) -> (5 5 8 4)
'(5 8 4) -> (8 8 13 5)
'(8 13 5) -> nil