Domanda

Recently I've (finally) started using Scala's Numeric trait, which does wonders. For example:

def square[A](x: A)(implicit num: Numeric[A]): A = num.times(x, x)

Now I can square any number be it Double, Integer, BigDecimal, or what not. Yet what if I want to do some more advanced math? For example, my logistic function for Double numbers looks like this:

def logisticFunction(x: Double): Double = 1.0 / (1.0 + math.exp(-x))

I could do the adding and dividing easily (I'd just have to use trait Fractional instead of Numeric), but what about the exponent? I sure don't want to write my own exp function (or any arbitrary function which takes Double arguments).

So, my question is this: how do I convert my A to Double, do my maths on that, and then convert back to A. Is it even possible?

EDIT:

That's how the signature of my function should look like:

def logisticFunction[A](x: A)(implicit num: Fractional[A]): A = 
  /* Magic happens here */

I've figured out the part about converting to double, which is as easy as num.toDouble(x). However the problem of converting back to A remains.

È stato utile?

Soluzione

I still doubt this approach is really useful. But with your description, you will want something like this:

type FromDouble[A] = Double => A
type ToDouble  [A] = A => Double

def logisticFunction[A: FromDouble: ToDouble](x: A): A = 1.0 / (1.0 + math.exp(-x))

logisticFunction(0.5)
implicit def bigDecimalToDouble(b: BigDecimal) = b.toDouble    
logisticFunction(BigDecimal(0.5))

Or with dedicated type class:

object FromDouble {
  implicit object _Double extends FromDouble[Double] {
    def apply(d: Double) = d
  }
  implicit object _BigDecimal extends FromDouble[BigDecimal] {
    def apply(d: Double) = BigDecimal(d)
  }
}
trait FromDouble[A] extends (Double => A)

object ToDouble {
  implicit object _Double extends ToDouble[Double] {
    def apply(d: Double) = d
  }
  implicit object _BigDecimal extends ToDouble[BigDecimal] {
    def apply(b: BigDecimal) = b.toDouble
  }
}
trait ToDouble[A] extends (A => Double)

def logisticFunction[A: FromDouble: ToDouble](x: A): A = 1.0 / (1.0 + math.exp(-x))

logisticFunction(0.5)
logisticFunction(BigDecimal(0.5))

Altri suggerimenti

You will need a type class that provides trigonometric functions such as exp. Scala's standard library does not go beyond Fractional. You could try to use Spire.

Example:

$ sbt core/console

import spire.math._
import spire.algebra._
import spire.implicits._

def logisticFunction[A](x: A)(implicit m: Field[A], t: Trig[A]): A =
  m.one / (m.one + exp(-x))

logisticFunction(0.5)
logisticFunction(BigDecimal(0.5))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top