То, что представляет Stream
, представляет собой ленивый и потенциально бесконечный список.Поскольку SML стремится , это нужно сделать немного окольным путем.
Давайте сначала посмотрим, как работают обычные списки:
datatype 'a list = [] | :: of 'a * 'a list
Минусы состоят издве части:
- Первый элемент в списке
- Остальная часть списка
В ленивом списке это очень похоже.
datatype 'a Stream = Nil | Cons of 'a * (unit -> 'a Stream)
Здесь минусы состоят из следующего:
- Первый элемент в списке
- Функция, которая создает остальную часть списка при оценке по
()
Итак, вы можете видеть, что принцип почти такой же, хотя с ним труднее работать.
Давайтепосмотрите на список примеров:
fun succ n = Cons (n, fn () => succ (n+1))
val naturals = succ 0
Что это дает?Давайте рассмотрим его.
naturals
было определено как succ 0
, что, в свою очередь, определено как Cons(0, fn () => succ 1)
.Отсюда видно, что первым элементом в списке является 0
.
Теперь давайте сделаем еще один шаг вперед.Мы оцениваем fn () => succ 1
, вторую часть нашего Cons
, по ()
, что дает succ 1
, что в свою очередь равно Cons(1, fn () => succ 2)
.Теперь мы можем видеть, что вторым элементом в списке является 1
.
Если мы повторим этот процесс, мы получим, что список представляет бесконечный список [0, 1, 2, ...]
.
Вы также можетечтобы увидеть это, попытайтесь сделать
val firstnats = take 10 naturals;
и посмотреть, что вы получите.