přiznám se, že mi není úplně jasné, jak tedy fungují nekonečné sekvence v Clojure.
Co je pochopitelné: v pythonu udělám sekvenci přes range(), to je úplně normální a pak take() skutečně sežere prvních několik prvků, taky jasný, protože "přetočím" generátor o n prvků dopředu.
Ale jak tedy Clojure zajistí, že každé jeho take() začíná od začátku. Klonováním toho objektu generátoru? tedy něco jako tee() v Pythonu?
(dokonce si vzpomínám, že nějak tak funguje Seq v Haskellu, ale ten zase nemá nekonečné sekvence)
V Clojure to funguje dobře, protože sémantika operací nth a take je zachována. Tj. (nth 10 s) vrátí vždy a za všech okolností desátý prvek (tedy přesněji řečeno jedenáctý), stejně jako (first s) vrátí vždy první prvek.
Navíc jsou sekvence neměnné (immutable) a funkce first a nth jsou referenčně transparentní, takže jakékoli jiné chování by bylo imho chybné.
Haskell má nekonečné lazy seznamy. V čem je rozdíl? Akorát podle mě je potřeba s línými sekvencemi fungovat jinak, nedají se restartovat a nemají se restartovat. Vezmu prvních 10 a s nimi pak pracuje další operace, ale už do té lazy sekvence nesahám, podle mě to nemá smysl.
smysl to má, třeba při rekurzivní definici posloupností
tohle v pythonu přímočaře nejde
(def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq)))
musel byste explicitně implementovat cachování nebo ten iterátor explicitně rozdělit na dva pomocí itertools.tee. Na druhou stranu se vám nemůže stát, že by někde zůstala reference na hlavu a celá sekvence by zůstala v paměti.