Это очень хороший вопрос. Я не думаю, что вы можете закодировать понятие базиса в большинстве систем типов, потому что по сути все, что делает средство проверки типов, должно иметь возможность завершаться, и делать суждения о том, равны ли два действительных вектора, слишком сложно. Вы можете иметь (2 v_1) + (2 v_2) или 2 (v_1 + v_2), например. Есть некоторые языки, которые используют зависимые типы [ wikipedia ], но они относительно академичны.
Я думаю, что большая часть вашей отладочной боли будет уменьшена, если вы просто закодируете основы, в которых ваша матрица работает вместе с матрицей. Например,
newtype Matrix = Matrix { transform :: [[Double]],
srcbasis :: [Double], dstbasis :: [Double] }
и затем, когда вы M из базы a до b с N , проверьте, что N от b до c , и вернуть матрицу с базой a до c .
ПРИМЕЧАНИЕ - кажется, что большинство людей здесь имеют программирование вместо математического фона, поэтому я приведу краткое объяснение здесь. Матрицы являются кодировками линейных преобразований между векторными пространствами. Например, если вы кодируете поворот на 45 градусов в R ^ 2 (2-мерные числа), то стандартный способ кодирования этого в матрице состоит в том, что стандартный базис вектор e_1, записанный «[1, 0]», отправляется на комбинацию e_1 и e_2, а именно [1 / sqrt (2), 1 / sqrt (2)]. Дело в том, что вы можете закодировать один и тот же поворот, сказав, куда идут разные векторы, например, вы можете сказать, куда вы отправляете [1,1] и [1, -1] вместо e_1 = [1,0] и e_2 = [0,1], и это будет иметь другое матричное представление.
Редактировать 1
Если у вас есть конечный набор баз, с которыми вы работаете, вы можете сделать это ...
{-# LANGUAGE EmptyDataDecls #-}
data BasisA
data BasisB
data BasisC
newtype Matrix a b = Matrix { coefficients :: [[Double]] }
multiply :: Matrix a b -> Matrix b c -> Matrix a c
multiply (Matrix a_coeff) (Matrix b_coeff) = (Matrix multiplied) :: Matrix a c
where multiplied = undefined -- your algorithm here
Затем, в ghci (интерактивный интерпретатор Haskell),
*Matrix> let m = Matrix [[1, 2], [3, 4]] :: Matrix BasisA BasisB
*Matrix> m `multiply` m
<interactive>:1:13:
Couldn't match expected type `BasisB'
against inferred type `BasisA'
*Matrix> let m2 = Matrix [[1, 2], [3, 4]] :: Matrix BasisB BasisC
*Matrix> m `multiply` m2
-- works after you finish defining show and the multiplication algorithm