Scala: how to write a tail-recursive function more idiomatically - scala

I have the following:
case class Node(parent: Option[Node], etc:Any)
#tailrec
def getAncestor(numGens:Int, node:Node): Option[Node] =
if(numGens <= 0) Some(node)
else node.parent match {
case Some(parent) => getAncestor(numGens-1, parent)
case None => None
}
I don't like the case None => None. It gives me the impression that there should be a more elegant way. However, if I replace the else with:
else node.parent.flatMap(p => getAncestor(numGens-1, p))
then the function is no longer tail-recursive. Is there a more idiomatic way of writing this function?

I don't think there is a way. Your approach is already concise enough. Here are two other options:
// 1. changing argument type
#tailrec
def getAncestor(numGens:Int, node: Option[Node]): Option[Node] =
if(numGens <= 0) node else getAncestor(numGens -1, node.flatMap(_.parent))
// 2. removing if
#tailrec
def getAncestor(numGens:Int, node:Node): Option[Node] =
node.parent match {
case _ if numGens <= 0 => Some(node)
case Some(parent) => getAncestor(numGens-1, parent)
case _ => None
}

#tailrec
def getAncestor(numGens:Int, node:Node): Option[Node] = {
node.parent match {
case Some(parent) if numGens > 0 => getAncestor(numGens - 1, parent)
case Some(_) | None if numGens == 0 => Some(node)
case _ => None
}
}

This case class doesn't seem very useful. Since each node has only one parent, what you have done is recreate List[Any] without any of the useful methods.
If you put your etc objects into a List, then getAncestor(i, n) simply becomes
ns drop i
The result will either be a shorter list with the desired node at the top or an empty list. No memory will be wasted because Scala's immutable list is a persistent data structure. You can retrieve the contents of the new head node with
ns.drop(i).headOption
No stackoverflows, no ugliness caused by trying to make a recursive function tail recursive (useful explicitly recursive functions almost always end up ugly when made tail recursive). Much more idiomatic Scala because it is using the right type for the job.
If you are trying to build some more complex kind of structure with your nodes, then you would do better to build a proper Algebraic Data Type using case classes extending a sealed trait (or sealed abstract base class). Need more information about your intentions before expanding on that idea, though.

Related

Getting max from a case class List of nodes, returning Scala Option[List]

I have a case class Node that I have written, and create a list from it and I need to find the node that has maximum disk.
I wrote the below code, is there a better way of doing it? Also, in my actual production code, my "nodeList" variable will be not just Option[List[Node]] but Future[Option[List[Node]]]. I guess still the answer/code won't change much except for the fact that I will do a map/flatMap to go inside the future and do the same thing.
If anyone has a better suggestion to write below code more Scala way, please share your thoughts.
scala> case class Node(disk: Integer, name: String)
defined class Node
scala> val nodeList = Option(List(Node(40, "node1"), Node(200, "node3"),Node(60, "node2")))
nodeList: Option[List[Node]] = Some(List(Node(40,node1), Node(200,node3), Node(60,node2)))
scala> val maxDisk = nodeList match {
| case None => println("List is empty"); None
| case Some(lst) => {
| Some(lst.max(Ordering.by((_:Node).disk)))
| }
| }`
maxDisk: Option[Node] = Some(Node(200,node3))
Judging by the code you wrote, I'm not sure if you really should use Optional[List[Node]]. You seem to treat None as an empty List, and you don't check for the empty list in the Some case. You might want to see if just a plain List[Node] suits your use better (where None would become Nil, and Some(lst) is just lst, and the unused Some(Nil) case no longer exists to confuse anyone).
If you do keep Optional[List[Node]], I'd do it like this:
nodeList
.filterNot(_.isEmpty) // maxBy throws if the list is empty; check for it
.map(_.maxBy(_.disk)) // maxBy looks nicer than max(Ordering.by)
If you switch to List[Node], it's slightly uglier:
Some(nodeList)
.filterNot(_.isEmpty) // We're using the filter utility of Option here,
.map(_.maxBy(_.disk)) // so I wrap with Some to get access to filterNot.
You can use recursion with List pattern matching.
case class Node(disk: Integer, name: String)
val nodeList = Option(List(Node(40, "node1"), Node(200, "node3"),Node(60, "node2")))
def findMaxValue(list: List[Node]): Option[Node] = list match {
case Nil => None
case List(x) => Some(x)
case first :: second :: rest => if(first.disk > second.disk) findMaxValue(first::rest) else findMaxValue(second::rest)
}
val node:Option[Node] = findMaxValue(nodeList.getOrElse(Nil))
println(node.get.disk) //print 200

Do something when exactly one option is non-empty

I want to compute something if exactly one of two options is non-empty. Obviously this could be done by a pattern match, but is there some better way?
(o1, o2) match {
case (Some(o), None) => Some(compute(o))
case (None, Some(o)) => Some(compute(o))
case _ => None
}
You could do something like this:
if (o1.isEmpty ^ o2.isEmpty)
List(o1,o2).flatMap(_.map(x=>Some(compute(x)))).head
else
None
But pattern matching is probably the better way to go.
Thanks to helpful comments from #Suma, I came up with another solutions in addition to the current ones:
Since the inputs are always in the form of Option(x):
Iterator(Seq(o1,o2).filter(_!=None))
.takeWhile(_.length==1)
.map( x => compute(x.head.get))
.toSeq.headOption
Using iterator also allows for a sequence of values to be passed to the input. The final mapping will be done if and only if one value in the sequence is defined.
Inspired by now deleted answer of pedrofurla, which was attempting to use o1 orElse o2 map { compute }, one possibility is to define xorElse, the rest is easy with it:
implicit class XorElse[T](o1: Option[T]) {
def xorElse[A >: T](o2: Option[A]): Option[A] = {
if (o1.isDefined != o2.isDefined) o1 orElse o2
else None
}
}
(o1 xorElse o2).map(compute)
Another possibility I have found is using a pattern match, but using Seq concatenation so that both cases are handled with the same code. The advantage of this approach is it can be extended to any number of options, it will always evaluate when there is exactly one:
o1.toSeq ++ o2 match {
case Seq(one) => Some(compute(one))
case _ => None
}
Just initialize a sequence and then flatten
Seq(o1, o2).flatten match {
case Seq(o) => Some(compute(o))
case _ => None
}

Scala case classes and tail recursion best practices

I'm fairly new to scala from java and also pretty new to pattern matching. One of the things I'm trying to get my head around is when to use it and what it's costs/benefits are. For example this
def myThing(a: Int): Int = a match {
case a: Int if a > 0 => a
case _ => myThing(a + 1)
}
Does the same thing as this (unless I've really misunderstood something)
def myThing(a: Int): Int = {
if (a > 0) a
else myThing(a + 1)
}
So my actual question:
But do they run the same way? Is my pattern matched example tail recursive? And if not, then why not when it is in the second example?
Are there any other things I should worry about, like resources? Or should I pretty much always try to use pattern matching?
I've searched around for these answers but haven't found any "best practices" for this!
Edit: I'm aware that the example used is a bit contrived - I've just added it to be clear about the question below it - thanks!
Yes they do run the same. Best practice for every syntactic sugar is the same: use it whenever it provides more readable or flexible code. In your examples in case of if statement you may omit braces and write just
def myThing(a: Int): Int = if (a > 0) a else myThing(a + 1)
Which is definitely more handy than pattern matching. Pattern matching is handy in situations where:
You have 3 or more alternatives
You should unpack\check values through extractors (check this question)
You should check the types
Also to ensure you function is tail-recursive you could use the #tailrec annotation
Another 'Scala' way to do it would be to define an extractor for a positive number
def myThing(a: Int): Int = a match {
case PositiveNum(positive) => positive
case negative => myThing(negative + 1)
}
object PositiveNum {
def unapply(n: Int): Option[Int] = if (n > 0) Some(n) else None
}
Yet another way to pattern-match against the evaluated predicate (condition),
def myThing(a: Int): Int = a > 0 match {
case true => a
case _ => myThing(a + 1)
}
where matches include no (additional) guards or type declarations.

Mapping many Eithers to one Either with many

Say I have a monadic function in called processOne defined like this:
def processOne(input: Input): Either[ErrorType, Output] = ...
Given a list of "Inputs", I would like to return a corresponding list of "Outputs" wrapped in an Either:
def processMany(inputs: Seq[Input]): Either[ErrorType, Seq[Output]] = ...
processMany will call processOne for each input it has, however, I would like it to terminate the first time (if any) that processOne returns a Left, and return that Left, otherwise return a Right with a list of the outputs.
My question: what is the best way to implement processMany? Is it possible to accomplish this behavior using a for expression, or is it going to be necessary for me to iterate the list myself recursively?
With Scalaz 7:
def processMany(inputs: Seq[Input]): Either[ErrorType, Seq[Output]] =
inputs.toStream traverseU processOne
Converting inputs to a Stream[Input] takes advantage of the non-strict traverse implementation for Stream, i.e. gives you the short-circuiting behaviour you want.
By the way, you tagged this "monads", but traversal requires only an applicative functor (which, as it happens, is probably defined in terms of the monad for Either). For further reference, see the paper The Essence of the Iterator Pattern, or, for a Scala-based interpretation, Eric Torreborre's blog post on the subject.
The easiest with standard Scala, which doesn't evaluate more than is necessary, would probably be
def processMany(inputs: Seq[Input]): Either[ErrorType, Seq[Output]] = {
Right(inputs.map{ x =>
processOne(x) match {
case Right(r) => r
case Left(l) => return Left(l)
}
})
}
A fold would be more compact, but wouldn't short-circuit when it hit a left (it'd just keep carrying it along while you iterated through the entire input).
For now, I've decided to just solve this using recursion, as I am reluctant to add a dependency to a library (Scalaz).
(Types and names in my application have been changed here in order to appear more generic)
def processMany(inputs: Seq[Input]): Either[ErrorType, Seq[Output]] = {
import scala.annotation.tailrec
#tailrec
def traverse(acc: Vector[Output], inputs: List[Input]): Either[ErrorType, Seq[Output]] = {
inputs match {
case Nil => Right(acc)
case input :: more =>
processOne(input) match {
case Right(output) => traverse(acc :+ output, more)
case Left(e) => Left(e)
}
}
}
traverse(Vector[Output](), inputs.toList)
}

Implementing ifTrue, ifFalse, ifSome, ifNone, etc. in Scala to avoid if(...) and simple pattern matching

In Scala, I have progressively lost my Java/C habit of thinking in a control-flow oriented way, and got used to go ahead and get the object I'm interested in first, and then usually apply something like a match or a map() or foreach() for collections. I like it a lot, since it now feels like a more natural and more to-the-point way of structuring my code.
Little by little, I've wished I could program the same way for conditions; i.e., obtain a Boolean value first, and then match it to do various things. A full-blown match, however, does seem a bit overkill for this task.
Compare:
obj.isSomethingValid match {
case true => doX
case false => doY
}
vs. what I would write with style closer to Java:
if (obj.isSomethingValid)
doX
else
doY
Then I remembered Smalltalk's ifTrue: and ifFalse: messages (and variants thereof). Would it be possible to write something like this in Scala?
obj.isSomethingValid ifTrue doX else doY
with variants:
val v = obj.isSomethingValid ifTrue someVal else someOtherVal
// with side effects
obj.isSomethingValid ifFalse {
numInvalid += 1
println("not valid")
}
Furthermore, could this style be made available to simple, two-state types like Option? I know the more idiomatic way to use Option is to treat it as a collection and call filter(), map(), exists() on it, but often, at the end, I find that I want to perform some doX if it is defined, and some doY if it isn't. Something like:
val ok = resultOpt ifSome { result =>
println("Obtained: " + result)
updateUIWith(result) // returns Boolean
} else {
numInvalid += 1
println("missing end result")
false
}
To me, this (still?) looks better than a full-blown match.
I am providing a base implementation I came up with; general comments on this style/technique and/or better implementations are welcome!
First: we probably cannot reuse else, as it is a keyword, and using the backticks to force it to be seen as an identifier is rather ugly, so I'll use otherwise instead.
Here's an implementation attempt. First, use the pimp-my-library pattern to add ifTrue and ifFalse to Boolean. They are parametrized on the return type R and accept a single by-name parameter, which should be evaluated if the specified condition is realized. But in doing so, we must allow for an otherwise call. So we return a new object called Otherwise0 (why 0 is explained later), which stores a possible intermediate result as a Option[R]. It is defined if the current condition (ifTrue or ifFalse) is realized, and is empty otherwise.
class BooleanWrapper(b: Boolean) {
def ifTrue[R](f: => R) = new Otherwise0[R](if (b) Some(f) else None)
def ifFalse[R](f: => R) = new Otherwise0[R](if (b) None else Some(f))
}
implicit def extendBoolean(b: Boolean): BooleanWrapper = new BooleanWrapper(b)
For now, this works and lets me write
someTest ifTrue {
println("OK")
}
But, without the following otherwise clause, it cannot return a value of type R, of course. So here's the definition of Otherwise0:
class Otherwise0[R](intermediateResult: Option[R]) {
def otherwise[S >: R](f: => S) = intermediateResult.getOrElse(f)
def apply[S >: R](f: => S) = otherwise(f)
}
It evaluates its passed named argument if and only if the intermediate result it got from the preceding ifTrue or ifFalse is undefined, which is exactly what is wanted. The type parametrization [S >: R] has the effect that S is inferred to be the most specific common supertype of the actual type of the named parameters, such that for instance, r in this snippet has an inferred type Fruit:
class Fruit
class Apple extends Fruit
class Orange extends Fruit
val r = someTest ifTrue {
new Apple
} otherwise {
new Orange
}
The apply() alias even allows you to skip the otherwise method name altogether for short chunks of code:
someTest.ifTrue(10).otherwise(3)
// equivalently:
someTest.ifTrue(10)(3)
Finally, here's the corresponding pimp for Option:
class OptionExt[A](option: Option[A]) {
def ifNone[R](f: => R) = new Otherwise1(option match {
case None => Some(f)
case Some(_) => None
}, option.get)
def ifSome[R](f: A => R) = new Otherwise0(option match {
case Some(value) => Some(f(value))
case None => None
})
}
implicit def extendOption[A](opt: Option[A]): OptionExt[A] = new OptionExt[A](opt)
class Otherwise1[R, A1](intermediateResult: Option[R], arg1: => A1) {
def otherwise[S >: R](f: A1 => S) = intermediateResult.getOrElse(f(arg1))
def apply[S >: R](f: A1 => S) = otherwise(f)
}
Note that we now also need Otherwise1 so that we can conveniently passed the unwrapped value not only to the ifSome function argument, but also to the function argument of an otherwise following an ifNone.
You may be looking at the problem too specifically. You would probably be better off with the pipe operator:
class Piping[A](a: A) { def |>[B](f: A => B) = f(a) }
implicit def pipe_everything[A](a: A) = new Piping(a)
Now you can
("fish".length > 5) |> (if (_) println("Hi") else println("Ho"))
which, admittedly, is not quite as elegant as what you're trying to achieve, but it has the great advantage of being amazingly versatile--any time you want to put an argument first (not just with booleans), you can use it.
Also, you already can use options the way you want:
Option("fish").filter(_.length > 5).
map (_ => println("Hi")).
getOrElse(println("Ho"))
Just because these things could take a return value doesn't mean you have to avoid them. It does take a little getting used to the syntax; this may be a valid reason to create your own implicits. But the core functionality is there. (If you do create your own, consider fold[B](f: A => B)(g: => B) instead; once you're used to it the lack of the intervening keyword is actually rather nice.)
Edit: Although the |> notation for pipe is somewhat standard, I actually prefer use as the method name, because then def reuse[B,C](f: A => B)(g: (A,B) => C) = g(a,f(a)) seems more natural.
Why don't just use it like this:
val idiomaticVariable = if (condition) {
firstExpression
} else {
secondExpression
}
?
IMO, its very idiomatic! :)