Scala's Implementation of haskell last method - scala

I am trying to do some examples programs in scala to get more familiar with the language, For that I am trying to re-implement some of the built in methods in Haskell, Most of these methods I am sure are also implemented in Scala too, But these are just for my practice. I think I can post some of code snippets (not all of them) to get a better way of doing things and to validate my understanding of scala. So please let me know if this is not the place to do these things.
Here is my scala implementation to get the last element of any list. Is this the right way of doing things, By using Any am I loosing the type of the object containing in the list? Is this how this kind of things implemented in scala?
def getLast(xs: List[Any]): Any = xs match {
case List() => null
case x :: List() => x
case _ :: ys => getLast(ys)
}

Parameterize the type of your function and use "Nil" instead of List() like so:
def getLast[T](xs: List[T]): T = xs match {
case Nil => null.asInstanceOf[T]
case x :: Nil => x
case _ :: ys => getLast(ys)
}
Also, consider making it return an Option type:
def getLast[T](xs: List[T]): Option[T] = xs match {
case Nil => None
case x :: Nil => Some(x)
case _ :: ys => getLast(ys)
}
Usage:
val listOfInts = List(1,2,3)
assert(getLast(listOfInts).isInstanceOf[Int])
val listOfStrings = List("one","two","three")
assert(getLast(listOfStrings).isInstanceOf[String])

Firstly, avoid the null, and especially null.asInstanceOf[T]. Observe the danger with primitives:
scala> null.asInstanceOf[Int]
res19: Int = 0
scala> null.asInstanceOf[Boolean]
res20: Boolean = false
So the signature should either be List[T] => T, whereby last on an empty iterator throws an exception:
def last[T](ts: List[T]): T = ts match {
case Nil => throw new NoSuchElementException
case t :: Nil => t
case t :: ts => last(ts)
}
Or instead: List[T] => Option[T]
def lastOption[T](ts: List[T]): Option[T] = ts match {
case Nil => None
case t :: Nil => Some(t)
case t :: ts => lastOption(ts)
}
def lastOption1[T](ts: List[T]): Option[T] = ts.reverse.headOption
def lastOptionInScala28[T](ts: List[T]): Option[T] = ts.lastOption // :)

Related

Function call not accepting :: operator in argument

I'm supposed to write a recursive functional concatenation function in Scala without using standard list operators.
def myConcat: (List[Any],List[Any]) => List[Any] = {
case (xs,Nil) => xs
case (xs,y::ys) => myConcat(xs::y,ys)
}
which throws the error
case (xs,y::ys) => myConcat(xs::y,ys)
^
Recursion.scala:3: error: value :: is not a member of Any
I am rather confident that this would, but that I am misunderstanding something about the syntax/typing. To the best of my knowledge xs::y should be of type List[Any].
I assume, you cannot use List.reverse either, so, start with implementing that:
#tailrec
def reverse(in: List[Any], out: List[Any]): List[Any] = in match {
case Nil => out
case head::tail => reverse(tail, head::out)
}
Now, for concat:
#tailrec
def concatReversed(x: List[Any], y: List[Any]): List[Any] = x match {
case Nil => y
case head::tail => concatReversed(tail, head::y)
}
def concat(x: List[Any], y: List[Any]) =
concatReversed(reverse(x, List.empty[Any]), y)
If you are not looking for the solution to be tail-recursive, it makes things simpler (albeit less efficient):
def concat(x: List[Any], y: List[Any]): List[Any] = x match {
case Nil => y
case head :: tail => head :: concat(tail, y)
}

Why can't I match on a Stream?

Specifically:
scala> def f(n: Seq[Any]) = n match {
case Nil => "Empty"
case h :: t => "Non-empty"
}
f: (n: Seq[Any])String
scala> f(Stream())
res1: String = Empty
scala> f(List(1))
res17: String = Non-empty
scala> f(Stream(1))
scala.MatchError: Stream(1, ?) (of class scala.collection.immutable.Stream$Cons)
at .f(<console>:13)
... 33 elided
There are a lot of other ways to implement this, but at written the code was statically safe and failed at run time. What's going on?
For Stream, the concat symbol should be #::, the pattern match should like:
def f(n: Seq[Any]) = n match {
case Nil => "Empty"
case h :: t => "Non-empty"
case h #:: t => "Non-empty stream"
}
for :: is for List / Seq type(List extends from Seq:) ), see:
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
You can only use :: to deconstruct a List and not a Stream. Since the Stream you provide does not match a List, you get a MatchError. If you want f to support streams using that type of matching (extractors), you can use #::.
def f(n: Seq[Any]) = n match {
case Nil => "Empty"
case h :: t => "Non-empty"
case h #:: t => "Non-empty"
}
In general, this approach is very fragile because both extractor types shown above will only work for those two types of Seq. Others maybe break. If all you care about is determining whether or not the Seq is empty or not, then simply use n.nonEmpty or n.isEmpty and deal with the Boolean result. Otherwise, trying to provide an exhaustive match on a trait that is not sealed is bound to fail.
You can also use the Seq extractor:
def f(n: Seq[Any]) = n match {
case Nil => "Empty"
case Seq(_*) => "Non-empty"
}
While other answers show correctly an extractor specific for Stream, which is #::, there exists an extractor for Seq (and anything derived from SeqLike) - it is +:, this works for both List (as ::) and Stream (as `#::). With this extractor you can easily write a function which works with both:
def f(n: Seq[Any]) = n match {
case h +: t => "Non-empty"
case _ => "Empty"
}
See also Scala pattern matching on sequences other than Lists

How to get eliminate ++ in Scala

I have a code in scala that I wrote but I would like to eliminate ++ from it. The code runs fine but I'm trying not to use ++ or any built in functions or operators (not even :::).
Is it just better to create a val, or are there better ways around it.
Here's a sample of that code.
def partitionAux[A](f: A => Boolean, lst: List[A],
rslt: (List[A], List[A]) ):(List[A], List[A]) = {
lst match {
case Nil => return result
case head :: rest => {
if (f(head))
return partitionHelper(f, rest, (result._1 ++ List[A](head), rslt._2))
else ...
Given that you have only a single element as a second arg of ++, you could implement it yourself:
def concat[A](lst: List[A], a: A): List[A] =
lst match {
case Nil => a :: Nil
case head :: tail => head :: concat(tail, a)
}
println(concat(1 :: 2 :: 3 :: 4 :: Nil, 100)) // 1 :: 2 :: 3 :: 4 :: 100
Also given that you mentioned that partitionAux should split the list into two, it sounds like you should have just head :: result._1, instead of result._1 ++ List[A](head), and then reverse the list in the end. It is easy to write the reverse function yourself, like:
#tailRec
def reverse[A](list: List[A], result: List[A] = Nil): List[A] =
list match {
case Nil => result
case head :: tail => reverse(tail, head :: result)
}
P.S. And you don't need to put return keyword in scala. It doesn't do anything in you case

Any convention for "given an empty list return an empty list" when matching patterns?

When pattern matching a list, it seems common to return an empty list when given an empty list. We can match an empty list to Nil or List(), but we can return empty as Nil, List() or by returning the given list argument itself.
What's the convention here?
When would you choose one method over another?
Examples:
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case List() => Nil
case x :: xs => ???
}
def givenEmptyNumsReturnsEmptyList(nums: List[Int]): List[Int] = nums match {
case List() => List()
case x :: xs => ???
}
def givenEmptyNumsReturnsNums(nums: List[Int]): List[Int] = nums match {
case List() => nums
case x :: xs => ???
}
I'm scala beginner and don't know any existing convention about it. My things about it:
The last one isn't intuitive
I prefer return that I match. If I have case List(), so I return List().
You can also match Nil:
-
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case Nil => Nil
case x :: xs => ???
}
But Nil and List() are the same.
For choice better way, just clarify what inside:
case N1:
def givenEmptyNumsReturnsEmptyList(nums: List[Int]): List[Int] = nums match {
case List() => List()
case x :: xs => ???
}
Will call unaplay method from object List, after will call apply method of object List.
case N2:
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case Nil => Nil
case x :: xs => ???
}
Will compare value before match with object Nil and will return object Nil
And in case of choice I prefer case N2 because it is little bit optimal.

Generic type inference in Scala

I've written the following code, which is actually a dumb merge-sort implementation in scala:
import scala.collection.immutable.List
object MergeSort {
def sort[T,E]( comparator: (E,E) => Int ) (l: List[T]): List[T] = {
def merge[T](first: List[T], second: List[T]): List[T] = (first, second) match {
case (_, List()) => first
case (List(), _) => second
case (f::restFirst, s::restSecond) if comparator(f.asInstanceOf[E],s.asInstanceOf[E]) < 0 => f :: merge(restFirst, second)
case (f::restFirst, s::restSecond) => s :: merge(first, restSecond)
}
l match {
case List() => return l
case List(x) => return l
case _ => {
val (first, second) = l.splitAt( l.length / 2 )
merge( sort(comparator)(first), sort(comparator)(second) )
}
}
}
}
This is instead of the following, more elegant, solution:
import scala.collection.immutable.List
object MergeSort {
def sort[T]( comparator: (T,T) => Int ) (l: List[T]): List[T] = {
def merge[T](first: List[T], second: List[T]): List[T] = (first, second) match {
case (_, List()) => first
case (List(), _) => second
case (f::restFirst, s::restSecond) if comparator(f,s) < 0 => f :: merge(restFirst, second)
case (f::restFirst, s::restSecond) => s :: merge(first, restSecond)
}
l match {
case List() => return l
case List(x) => return l
case _ => {
val (first, second) = l.splitAt( l.length / 2 )
merge( sort(comparator)(first), sort(comparator)(second) )
}
}
}
}
Which doesn't compile, giving me the following error message:
MergeSort.scala:10: type mismatch;
[error] found : f.type (with underlying type T)
[error] required: T
[error] case (f::restFirst, s::restSecond) if comparator(f,s) < 0 => f :: merge(restFirst, second)
Why is the explicit cast necessary since the underlying type is T ?
This is one of the most annoying Scala gotchas I can think of (maybe after semicolon inference-related issues with operators). You're three characters from the correct answer.
The problem is the type parameter on merge. It introduces a new T that shadows the T type parameter on sort. The compiler therefore doesn't know that comparator can be applied to instances of that new T. You can boss it around with a cast, which is why your first version works, but otherwise it sees that T as a blank slate.
Just write def merge(first: List[T], ... and you'll be fine.