5
\$\begingroup\$

I'm currently in the process of learning scala, and I'm looking for some best practices/proper idioms for the use of pattern matching with BigInts. I'm writing some algorithmic code (for Project Euler) as a way to learn the language.

The problem I am running into is what is the best idiomatic way to match a BigInt, since there's a type conversion problem if I try to write case 1 => and BigInt isn't a case class. Is there a canonical way to do this, or should I just give up and use if statements?

The following is one possible pattern:

def pollardRho(n: BigInt): BigInt = {
  val one = BigInt(1)

  n match {
    case `one` => n
    //additional cases here
  }
}

This one just feels wrong: A hack to get around the fact that I can't match it directly, especially with the backticks in there to keep scala from trying to assign the resulting value to one or when I have to do it for more than a single value or in a single case.

Another possibility:

def pollardRho(n: BigInt): BigInt = {

  n match {
    case _ if n == 1 => n
    //additional cases here
  }
}

This sort of pattern appeals to the Erlang programmer in me, but I have some concerns:

  1. Given the warnings I've read not to treat Scala like any other language, I am not sure that my instinct here is not an anti-pattern (or at least considered less readable) in the scala world.
  2. It feels like there might be cleaner way to use a custom PartialFunction instead of n match if what I am fundamentally going to do is just a series of tests around n. I am not sure, however, exactly what that would look like (most of the examples of PartialFunctions I've seen don't look quite like this application).

My question is, out of the array of possibilities in scala, which one is the best/most readable/most idiomatic?

\$\endgroup\$
4
\$\begingroup\$

Write your own extractor:

object Big {
  def unapply(n:BigInt) = Some(n.toInt)
}

//usage
def f(b:BigInt) = b match {
   case Big(0) => "none"
   case Big(1) => "one"
   case _ => "many"
}

Obviously, this isn't the fastest solution, but I think, it's quite idiomatic...

\$\endgroup\$
  • 1
    \$\begingroup\$ This also doesn't produce the desired output, since it assumes that I am working with something that can convert to Int without overflow, e.g., BigInt("4294967297") will match Big(1). \$\endgroup\$ – dclements Aug 11 '12 at 20:18
  • \$\begingroup\$ The logic in this one might not be 100% correct but extract is definitely the way to go if you want to be able to use match. \$\endgroup\$ – sourcedelica Aug 11 '12 at 21:01
  • \$\begingroup\$ I'd use n.toLong as you can't write literal number, bigger than Long. Besides it's natural to use String extractor along with Long one, so you could use use case Big("123") => as well. \$\endgroup\$ – n1ckolas Nov 6 '14 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.