Мне нужна функция +++
, которая складывает два математических вектора.
Я мог бы реализовать векторы как [x, y, z]
и использовать:
(+++) :: (Num a) => [a] -> [a] -> [a]
(+++) = zipWith (+)
И, таким образом, разместить любой n-мерный вектор (так что это будет работать для [x, y]
тоже).
Или я мог бы реализовать векторы как (x, y, z)
и использовать:
type Triple a = (a, a, a)
merge :: (a -> b -> c) -> Triple a -> Triple b -> Triple c
merge f (a, b, c) (x, y, z) = (f a x, f b y, f c z)
(+++) :: (Num a) => Triple a -> Triple a -> Triple a
(+++) = merge (+)
Конечно, это немного сложнее, но когда я реализую все остальные векторные функции, это не имеет значения ( 50 строк вместо 40).
Проблема со списком заключается в том, что я могу добавить 2D-вектор к 3D-вектору. В этом случае zipWith
просто отрезает компонент z
3D-вектора. Хотя это может иметь смысл (более вероятно, что он должен расширять 2D-вектор до [x, y, 0]
), для других функций, я думаю, может быть проблематично, чтобы это происходило молча. Проблема с кортежным подходом заключается в том, что он ограничивает вектор тремя компонентами.
Интуитивно я думаю, что имеет смысл представлять векторы как (x, y, z)
, так как математический вектор имеет фиксированное количество компонентов и на самом деле не имеет смысла чтобы добавить (подставить) компонент к вектору.
С другой стороны, хотя очень маловероятно, что мне понадобится что-либо, кроме 3D-векторов, ограничиваться этим кажется не совсем правильным.
Думаю, мне нужны функции, принимающие два списка одинаковой длины, или, что еще лучше, функции, работающие с кортежами произвольного размера.
Любые предложенияс точки зрения практичности, масштабируемости, элегантности и т. д.?