5

I'm trying to do something that seems like it should have a straight forward syntax/function in scala. I just don't know what that is. I'm trying to convert the contained value of an Option (if it is not None) to another type.

Simply I want to know what the code would be if I wanted to implement the following function

def myFunc(inVal:Option[Double]):Option[BigDecimal] = {
    //Code I need goes here
}

Note: I am not actually implementing this function, it just is the clearest way for me to demonstrate what I need

giampaolo
  • 6,906
  • 5
  • 45
  • 73
Craig Suchanec
  • 10,474
  • 3
  • 31
  • 39

3 Answers3

14
def myFunc(inVal: Option[Double]): Option[BigDecimal] =
  inVal map {d => d: BigDecimal}

In general if you want to transform value in container (Option, Seq, List, Try, Future, etc) you should use method map on this container.

Method map accepts lambda (function) as parameter and applies this function to all elements. map should not change the count of elements: map on Some will never return None.

You could use method BigDecimal.apply to convert Double to BigDecimal like this:

BigDecimal(1.1)
// res0: scala.math.BigDecimal = 1.1

But there is also an implicit conversion from Double to BigDecimal, so you could just specify desired type like this:

1.1: BigDecimal
// res0: scala.math.BigDecimal = 1.1

val bd: BigDecimal = 1.2

PS: type inference allows you to use d => d instead of d => d: BigDecimal here, but it will make your code very unclear.

Randall Schulz
  • 26,420
  • 4
  • 61
  • 81
senia
  • 37,745
  • 4
  • 88
  • 129
  • @som-snytt: Updated, though I can't imagine someone would try to use `map` this way. – senia Feb 05 '14 at 19:24
  • @senia Really helpful answer. I wasn't conceptualizing the Option just as another container and what I really wanted to do was transform the contents of the container. Really helpful to think that way and hopefully will stop me from getting stuck in other places in the future. – Craig Suchanec Feb 05 '14 at 19:29
  • @RandallSchulz: I guess "container" is better for beginners, than "M-word", though `Reader` is not a container. – senia Feb 05 '14 at 19:34
  • @RandallSchulz all this one needs is the F-word :) – Mysterious Dan Feb 05 '14 at 20:08
  • @senia reader could easily be seen as a container. Take an infinite stream, which I think most people would agree is "containerish". That's isomorphic to a reader from natural numbers, with the same flavor of monad/applicative/functor. – Mysterious Dan Feb 05 '14 at 20:09
  • @MyseriousDan: could you please describe isomorphism between `Stream` and `scalaz.Reader`? – senia Feb 05 '14 at 20:23
  • Keep in mind I said infinite stream (in the sense we'd use it in Haskell) and not potentially infinite stream, as Scala's is. An infinite one is trivially equivalent to a function from naturals to the element type, where that function is just the indexing function. That function is also a reader. You can also treat finite lists this way if you think of "numbers less than K" as a distinct type (called `Fin` in many languages). Potentially infinite lists like Haskell's list or Scala's stream are trickier: You can have `Either[InfiniteStream,List]` but that's subtly different from `Stream`. – Mysterious Dan Feb 05 '14 at 21:36
  • The difference is that they contain all the same elements, in theory, but you can't decide whether `Stream` is finite in finite time, and you can with the `Either` version. – Mysterious Dan Feb 05 '14 at 21:37
  • @senia forgot to highlight you so you'd see the responses :) – Mysterious Dan Feb 06 '14 at 17:39
  • @MyseriousDan: thank you, I got the idea. From this point any pure function is just a map. – senia Feb 06 '14 at 19:09
2
def myFunc(inVal: Option[Double]): Option[BigDecimal] = inVal map { BigDecimal(_) }

or

def myFunc(inVal: Option[Double]): Option[BigDecimal] = inVal map { BigDecimal.apply }

It works because Option is a Functor (no monadic trick in this simple use case)

Yann Moisan
  • 8,161
  • 8
  • 47
  • 91
0

Extending @senia's and @Yann Moisan's answers, if you want to keep something wrapped inside Option[] while still supplying a default value during conversion phase (could be a requirement down-the-line in your framework), you can use this:

def myFunc(inVal: Option[Double]): Option[BigDecimal] = {
  Some(inVal.map(BigDecimal(_)).getOrElse(BigDecimal(0.0)))
}

It would not only convert your Option[Double] into Option[BigDecimal] but also create a default BigDecimal (with value 0.0) in case the origin Option[Double] turns out to be null.

y2k-shubham
  • 10,183
  • 11
  • 55
  • 131