@@ -302,20 +302,28 @@ def _evaluate_iterator(expr, **kwargs):
302302 except (TypeError , AttributeError ):
303303 return expr # un-reducible iterators are opaque, like any object we can't recurse into
304304
305- if ctor is iter :
306- result = ctor (* evaluate (args ))
307- else :
308- from effectful .internals .unification import nested_type
305+ from effectful .internals .unification import nested_type
309306
310- ExprType = nested_type (expr ).value
307+ ExprType = nested_type (expr ).value
311308
312- @Operation .define
313- def ctor_op (* args ) -> ExprType :
314- return ctor (* args )
309+ @Operation .define
310+ def ctor_op (* args ) -> ExprType :
311+ return ctor (* args )
315312
316- result = ctor_op (* evaluate (args ))
313+ # Reify through ``ctor_op`` rather than calling the live constructor: when
314+ # the evaluated args contain a ``Term`` the result is a structural ``Term``
315+ # node whose source iterables stay traversable (so ``fvsof`` finds their
316+ # free variables and term-reconstruction interpretations can rewrite them).
317+ # For fully concrete args ``ctor_op``'s default rule rebuilds the live
318+ # iterator, preserving laziness.
319+ result = ctor_op (* evaluate (args ))
317320
318- if state and state [0 ] is not None and hasattr (result , "__setstate__" ):
321+ if (
322+ not isinstance (result , Term )
323+ and state
324+ and state [0 ] is not None
325+ and hasattr (result , "__setstate__" )
326+ ):
319327 result .__setstate__ (
320328 evaluate (state [0 ])
321329 ) # preserve position so advanced iterators don't reset
0 commit comments