Skip to content

NamedTuples failing for zipvmap - #144

Draft
benikm91 wants to merge 1 commit into
dimwit-dev:mainfrom
benikm91:zipvmap-named-tuples
Draft

NamedTuples failing for zipvmap#144
benikm91 wants to merge 1 commit into
dimwit-dev:mainfrom
benikm91:zipvmap-named-tuples

Conversation

@benikm91

@benikm91 benikm91 commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

The current zipvmap and vmap do not yet support named tuples as the return type of f. I failed to achieve this by extending the PrependAxis match type. This PR provides a solution, but I am unsure whether removing the match type is necessary. This PR is a conversation starter about whether and how we can add named tuple support more cleanly with match types. And highlighting the lack of support.

Named tuples could be quite powerful, as the tuple names can be tracked across vmap and zipvmap operations. This is not possible for case classes with a fixed tensor structure. Here with explicit type alias to clarify what is (automatically) happening:

val t = Tensor(Shape(Axis[A] -> 2, Axis[B] -> 3)).fill(0f)
type FOut = (first: Tensor1[B, Float32], second: Tensor1[B, Float32]) // return named tuple of tensor
def f(x: Tensor1[B, Float32]): FOut =
  (first = x +! 5f, second = x -! 5f)
type TrackedOut = (first: Tensor2[A, B, Float32], second: Tensor2[A, B, Float32]) // automatically track names across tensor expansion
val res: TrackedOut = t.vmap(Axis[A]): x => // vmap automatically transforms FOut to TrackedOut (adds A axis to each field) keeps names
  f(x)

Replaced the `PrependAxis` match type with a typeclass to overcome
resolution limitations and explicitly support Scala 3 NamedTuples.

Functions passed to `vmap` and `zipvmap` can now return named tuples
(e.g., `(first = x, second = y)`), and the operation will correctly
prepend the mapped axis to all enclosed tensors. Added test coverage
to verify the new behavior.
@benikm91
benikm91 force-pushed the zipvmap-named-tuples branch from 5d6a928 to 281b11c Compare August 13, 2026 11:14
@marcelluethi

Copy link
Copy Markdown
Contributor

I wonder if there is a disadvantage of given up match types in terms of type inference. Have you noticed anything?
In case type inference or compile time messages are getting worse, I think it is not worth the trouble. It seems to me that in 99% of the cases, what is returned is just a single value, not a tuple. Now we support tuples of all shapes. And even if we could support named tuples, there is still the gap that we cannot support case classes.

We could always work around it by manually calling to tuple

val res = zipvmap(Axis[A])(params.toTuple) { case (x1, x2) => x1 + x2 }
val (t1, t2) = t.vmap(Axis[A])(x => (x +! 5f, x -! 5f))
val named = (name1= t1,  name2 = t2)

However, if cost is only implementation complexity, I am all in for it. What is your experience?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants