Это вполне возможно (я сам это сделал) с соответствующими последствиями, хотя результат не всегда является настолько плавным, как язык, который был разработан с нуля таким образом.
Например,Предположим, вы хотите рассматривать массивы целых чисел как векторы и хотите иметь возможность добавлять их друг к другу и к скалярам.Вы должны определить операцию самостоятельно - Scala не может угадать, что +
должно означать для массива.(Хорошая вещь также, потому что *
обычно не имеет очевидного поэлементного значения для матриц, и это означает что-то еще, когда дело доходит до свертки!) Вы можете
class ArraysAdd(a: Array[Int]) {
def +(i: Int) = a.map(_ + i)
def +(b: Array[Int]) = {
if (b.length==a.length) (a,b).zipped.map(_ + _).toArray
else throw new IllegalArgumentException
}
}
class ScalarAddsToArray(i: Int) {
def +(a: Array[Int]) = a.map(_ + i)
}
implicit def array2addable(a: Array[Int]) = new ArraysAdd(a)
implicit def scalar2arrayaddable(i: Int) = new ScalarAddsToArray(i)
и затем вы можете выполнить математику для массивов целых чисел:
scala> Array(1,2,3) + 5
res2: Array[Int] = Array(6, 7, 8)
scala> Array(1,7) + Array(3,2)
res3: Array[Int] = Array(4, 9)
scala> 4 + Array(-2,-3,-1)
res4: Array[Int] = Array(2, 1, 3)
Если вы хотите охватить все типы данных, это становится сложнее (вам нужно использовать как минимум дженерики, так и Numeric - или написать генератор кода дляслучаев, которые вам нужны), и для эффективности вы можете захотеть создать собственный класс «матрицы» вместо того, чтобы придерживаться необработанных массивов, которые вы продолжаете упаковывать с дополнительными функциями.
Это охватывает основные операции.Для математических функций, таких как math.sqrt
, если вы не против набрать a map sqrt
вместо sqrt(a)
, вам не нужно ничего делать.В противном случае вы можете перегрузить их все сами;утомительно, но затем позволяет вам использовать их прозрачно.
Или вы можете использовать библиотеку, которая уже сделала многое для вас.(Скала - лучший из известных мне кандидатов на матрицы.)