2015-07-11 3 views
1

Я ищу, чтобы определить функцию, которая принимает два аргумента типа Любые попытки добавить, например:Scala - арифметические операции над Params типа Любой

def plus(x:Any,y:Any):Try[Any] = { 
    ... 
} 

приносит успеха, если операнды типов который может быть добавлен (арифметически, а не строка concat или что-то в этом роде) и Failure if not. Например:

val x:Any = 1 
val y:Any = 2 
val z = plus(x,y) // z = Success(3) 

или

val x:Any = "wrong" 
val y:Any = 2 
val z = plus(x,y) // z = Failure(...) 

и я хотел бы иметь продвижение типа работы, как это обычно делает с добавлением: Int + Int => Int, Int + Double => Double, и т.д.

Я знаю, что должен быть умный и простой способ сделать это, без необходимости проверять все возможные комбинации типов с совпадением. Я довольно новый (только неделя) для Scala, поэтому буду благодарен за любые предложения.

+0

возможно дубликат [Scala - уборщик способ написания родовой числовой метод работы] (http://stackoverflow.com/questions/31346087/scala-cleaner-way-of-writing-generic-numeric-operation- метод) – Luegg

+0

@Leugg - это было не так. У меня была двойная проблема. Первое - это отправка фактических параметров (во время компиляции типы всегда будут «Любые»), а затем для выполнения арифметической функции, как если бы компилятор знал типы динамически. Поэтому я хочу, чтобы плюс (1, 2.0) дал Double и plus (1, 2), чтобы получить Int –

+0

. В этом случае я сомневаюсь, что есть простой и чистый способ делать то, что вы хотите. Используя 'Any', вы отменяете систему типов. Вы уверены, что связаны с «Любом» или есть способ сохранить исходные типы? Похоже, вы пытаетесь использовать Scala как язык динамических типов. – Luegg

ответ

1

В ваших образцах вы знаете тип аргументов во время компиляции. В этом случае вы можете сделать лучшую работу с использованием системы типа:

scala> def plus[T: Numeric](a: T, b: T) = implicitly[Numeric[T]].plus(a, b) 
plus: [T](a: T, b: T)(implicit evidence$1: Numeric[T])T 

scala> plus(1, 2) 
res0: Int = 3 

scala> plus(1, 2.5) 
res1: Double = 3.5 

scala> plus(1, "2") 
<console>:9: error: could not find implicit value for evidence parameter of type Numeric[Any] 
       plus(1, "2") 
       ^
+0

спасибо за ответ. Я сделал ошибку, когда привел примеры и не смог ввести аргументы явно как «Любой». Теперь вы должны уяснить проблему более четко. –

0

Обновлено: Oops! Я пропустил последнюю часть вашего вопроса. То, что я объяснил, не работает, если вы попытаетесь добавить два разных типа, например Int + Double => Double.


Я думаю, что вы можете использовать моноидными Scalaz «s

Просто, это выглядит как этот

trait Monoid[F] extends Semigroup[F] { 
    def zero: F 
    def append(f1: F, f2: => F): F 
} 

Так что, если вы хотите использовать его, все, что вам нужно сделать, это импортировать Scalaz

import scalaz._ 
import Scalaz._ 

Тогда вы можете просто сделать

1 |+| 1  // result: 2 

"a" |+| "b" // result: ab 

BigInt(100) |+| BigInt(100) // BigInt(200) 

Scalaz обеспечивает неявное преобразование типов для большинства известных типов, таких как Int, BigInt, BigDecimal, String и т. Д., Но если у вас есть свой тип и вы хотите сделать его доступным, вы можете сделать это легко.

Допустим, у вас есть тип, как

case class Something(value: Int) 

Вы можете использовать неявное преобразование типов, как.

implicit def SomethingMonoid = new Monoid[Something] { 
    override def zero: Something = Something(0) 
    override def append(f1: Something, f2: => Something): Something = Something(f1.value |+| f2.value) // you can even use |+| here as value is Int 
    } 

Теперь, вы можете просто сделать

Something(10) |+| Something(100) // result: Something(110) 

Если вы хотите использовать его, просто импортировать что SomethingMonoid с Scalaz

import scalaz._ 
import Scalaz._ 
import your.package.SomethingMonoid 

// Or 
import scalaz._ 
import Scalaz._ 

// ... 
val somethingMonoid = your.package.SomethingMonoid 

Затем вы можете сделать

Something(111) |+| Something(222) // result: Something(333) 

Использование Monoid для обработки результата т лучше, чем иметь свой метод и вернуть Попробуйте [T], потому что вы не можете скомпилировать типобезопасность времени, тогда как Monoid даст вам ошибку во время компиляции, если вы делаете что-то подобное,

Something(10) |+| 100 // a compile-time error 

Если вы действительно хотите иметь свой собственный плюс, вы можете сделать что-то вроде этого

def plus[T](x: T, y: T)(implicit monoid: Monoid[T]): Try[T] = Try(monoid.append(x, y)) 

с Scalaz, как я объяснил выше, но вы получите ошибку компиляции, когда типы не не совпадают так нет смысла использовать Попробуйте, если вычисление может бросить какое-то исключение.

plus(1, 2)  // result: 3 
plus(Something(1), Something(9)) // result: Something(10) 
plus("one", 2) // result: a compile-time error