Почему (-) не удается проверить тип, когда я размещаю двойную матрицу слева и двойную справа?

Поскольку hmatrix предоставляет экземпляр Num для типов Matrix, я могу выразить поэлементное вычитание, например:

m = (2><2)[1..] :: Double Matrix
m' = m - 3

Это прекрасно работает, как 3 это Numи приводит к матрице, созданной путем вычитания 3 из каждого элемента m,

Почему это тоже не работает:

m' = m - (3::Double)

Я получаю ошибку:

Couldn't match expected type ‘Matrix Double’
            with actual type ‘Double’
In the second argument of ‘(-)’, namely ‘(3 :: Double)’
In the expression: m - (3 :: Double)

Я ожидал, что компилятор поймет, что Double также Num, Почему это, похоже, не так?

2 ответа

Решение

Что происходит, когда вы делаете m - 3 с m :: Matrix Double в том, что 3 :: Matrix Double, Дело в том, что Matrix Double это пример Num означает, что компиляторы умеют переводить литеральное 3, Однако, когда вы делаете m - (3 :: Double), вы получаете ошибку типа, потому что (-) :: (Num a) => a -> a -> aтаким образом, тип вычитаемого элемента должен быть экземплярами Num и соответствовать. Следовательно, вы можете вычесть два Doubleс, два Matrix Doubleс но не Matrix Double и Double,

В конце концов, это кажется мне вполне логичным, не имеет смысла вычитать матрицу и скаляр.

Это распространенное заблуждение людей, плохо знакомых со стилем перегрузки на основе классов типов в Haskell, особенно тех, кто привык к перегрузкам на основе подклассов, используемым в популярных языках OO.

Оператор вычитания имеет тип Num a => a -> a -> a; поэтому он принимает два аргумента любого типа, который находится в классе типа Num, Кажется, что происходит, когда вы делаете m - 3 является то, что оператор вычитания принимает Matrix Double слева и простой числовой тип справа. Но это на самом деле неверно.

Когда подпись типа, как Num a => a -> a -> a использует одну и ту же переменную типа несколько раз, вы можете выбрать любой тип, который вам нравится (при условии =>: Num a в этом случае) использовать для a но это должен быть точно такой же тип везде, что a появляется. Matrix Double -> Double -> ??? не является действительным экземпляром типа Num a => a -> a -> a (и если бы это было, как бы вы узнали, что он вернулся?).

Причина m - 3 работает, потому что оба аргумента должны быть одного типа, и m определенно типа Matrix Doubleкомпилятор видит что 3 также должен быть типа Matrix Double, Таким образом, вместо использования 3 появляется в исходном тексте, чтобы построить Double (или же Integerили один из многих других числовых типов), он использует исходный текст 3 построить Matrix Double, Эффективно вывод типа изменил способ, которым компилятор читает текст исходного кода 3,

Но если вы используете m' = m - (3::Double) тогда вы не позволяете ему просто выяснить, какой тип 3 необходимо сделать использование оператора вычитания действительным, вы говорите, что это 3 конкретно Double, Оба факта не могут быть правдой (ваш :: Double утверждение и требование, чтобы оператор вычитания получал два аргумента одного типа), поэтому вы получаете ошибку типа.

Другие вопросы по тегам