Самый очевидный способ:
type Num = {
def +(a: Num): Num
def *(a: Num): Num
}
def pyth[A <: Num](a: A, b: A)(sqrt: A=>A) = sqrt(a * a + b * b)
// usage
pyth(3, 4)(Math.sqrt)
Это ужасно по многим причинам. Во-первых, у нас есть проблема рекурсивного типа Num
. Это допустимо только в том случае, если вы компилируете этот код с параметром -Xrecursive
, для которого установлено некоторое целое значение (5, вероятно, более чем достаточно для чисел). Во-вторых, тип Num
является структурным, что означает, что любое использование определенных им членов будет скомпилировано в соответствующие рефлексивные вызовы. Мягко говоря, эта версия pyth
непристойно неэффективна и работает в несколько раз в сто тысяч медленнее, чем обычная реализация. Однако нет никакого способа обойти структурный тип, если вы хотите определить pyth
для любого типа , который определяет +
, *
и для которого существует функция sqrt
.
Наконец, мы подошли к самому фундаментальному вопросу: он слишком сложный. Зачем реализовывать эту функцию таким образом? Практически говоря, единственные типы, к которым он когда-либо должен применяться, - это реальные числа Scala. Таким образом, проще всего сделать следующее:
def pyth(a: Double, b: Double) = Math.sqrt(a * a + b * b)
Все проблемы решены! Эта функция применима к значениям типа Double
, Int
, Float
, даже к нечетным, таким как Short
, благодаря чудесам неявного преобразования. Хотя это правда, что эта функция технически менее гибкая, чем наша структурно типизированная версия, она значительно более эффективна и в высшей степени удобочитаема. Возможно, мы потеряли способность вычислять теорему Пифагра для непредвиденных типов, определяющих +
и *
, но я не думаю, что вы упустите эту способность.