I hadn’t seen “YAGNI” before, and that’s partly it, but it’s also the concreteness and safety of not allowing construction in ways that aren’t intended. You had something like this:
template <typename T>
struct seq_view {
const T& x_;
seq_view(const T& x) : x_(x) { }
const T& operator[](int n) { return x_; }
}
template <typename T>
struct seq_view<vector<T> > {
const vector<T>& xs_;
seq_view(const vector<T>& x) : xs_(x) { }
const T& operator[](int n) { return xs_[n]; }
}
That would work for all the views of Eigen vectors that we currently have and all the views of Eigen matrices we are currently thinking about.
I was suggesting two more specific versions that would have the same effect as instantiating T to Eigen::Matrix<S, -1, 1>
and Eigen::Matrix<S, -1, 1>
but would more clearly specify the return type. Mainly because I think it’ll be cleaner in the code to use vector_seq_view
and matrix_seq_view
to clearly indicate what the return type of operator[](int)
is going to be.
The automatic lifting in the general case is problematic, because we can have std::vector<double>
wrapped to give a scalar sequence and also need to wrap VectorXd
, etc. to provide scalar sequence views. Where it won’t work is if we have sequence views of std::vector<T>
, but then what I proposed won’t work there either.
It’s funny—I think about these problems all the time, but don’t think about them much in these functional terms (like generic type lifting) very much, whereas I used to think about type lifting all the time (mainly in the map sense of lifting a functor on scalars up to a functor on sequences, which inverts control relative to what we’re talking about here).
I think what you’re suggesting will work for everythign we need, and if you don’t think it’ll be too confusing in client code (by which I mean things like multi_normal_lpdf
) then go ahead and do it that way.
I don’t know the Either
construction, but see it’s a variant type spec. We use that all over the grammars. It raises control as well being implemented with a functor that operates on each of the variants. But the problem here in that language is that while this
Either T vector<T> -> T
will work for cases where T
is an Eigen container, what we need for cases where T
is a scalar look like:
Either double
vector<double>
Eigen::Matrix<double, -1, 1>
Eigen::Matrix<double, 1, -1>
-> double
and same for var
and fvar<T>
in place of double
. That is, our containers in this pattern aren’t homogeneous in their usage. This is what I was trying to get at before. But it’s only the scalar vs. matrix views that matter.
To end a long story, go ahead and implement this however you think is best. I think it’ll work either way. Just because I’d do it one way doesn’t mean you have to!