So I'm following http://jelv.is/blog/Lazy-Dynamic-Programming/ and implementing the Fibonacci example in Scala. Here is my implementation:
class Lazy[T] (expr : => T) {
lazy val value = expr
def apply(): T = value
}
object Lazy{ def apply[T](expr : => T) = new Lazy({expr}) }
def fib(n: Int): Int = {
def doFib(i: Int): Lazy[Int] = Lazy {
if (i <= 2) 1
else fibs(i - 1)() + fibs(i - 2)()
}
lazy val fibs = Array.tabulate[Lazy[Int]](n)(doFib)
doFib(n).value
}
fib(5)
In this case, fib(5) correctly returns result 5.
Then I want to see if Lazy[T] can be made into a monad by trying the following code, which results in StackOverflow runtime error:
class Lazy[T] (expr : => T) {
lazy val value = expr
def apply(): T = value
def flatMap[A](f: T => Lazy[A]): Lazy[A] = Lazy { f(value).value }
def map[A](f: T => A): Lazy[A] = Lazy { f(value) }
}
object Lazy{ def apply[T](expr : => T) = new Lazy({expr}) }
def fib(n: Int): Int = {
def doFib(i: Int): Lazy[Int] =
if (i <= 2) Lazy(1)
else for {
a <- fibs(i - 1)
b <- fibs(i - 2)
} yield a + b
lazy val fibs = Array.tabulate[Lazy[Int]](n)(doFib)
doFib(n).value
}
fib(5)
It appears that fibs(i - 1) is calculated too early, which results in infinite recursion. I wonder if there is a for comprehension syntax that's equivalent to the first code snippet?
You are right, "fibs(i - 1) is calculated too early". It is evaluated immediately when you call doFib, because the doFib(i) needs fibs(i - 1) in order to be able to return anything, which in turn needs the return value of doFib(i - 1) and so on, so that the recursion unfolds completely while you are constructing the array of lazy ints (before you invoke doFib(n).value).
If you want it lazy, then return a Lazy that does not require immediate evaluation of fibs(i - 1):
class Lazy[T] (expr : => T) {
lazy val value = expr
def apply(): T = value
def flatMap[A](f: T => Lazy[A]): Lazy[A] = Lazy { f(value).value }
def map[A](f: T => A): Lazy[A] = Lazy { f(value) }
}
object Lazy{ def apply[T](expr : => T) = new Lazy({expr}) }
def fib(n: Int): Int = {
def doFib(i: Int): Lazy[Int] =
if (i <= 2) Lazy(1)
else Lazy{ (for {
a <- fibs(i - 1)
b <- fibs(i - 2)
} yield a + b).value
}
lazy val fibs = Array.tabulate[Lazy[Int]](n)(doFib)
doFib(n).value
}
println(fib(40)) // 102334155
Alternatively, you can wrap the whole if-else in a Lazy:
def doFib(i: Int): Lazy[Int] = Lazy {
if (i <= 2) 1
else (for {
a <- fibs(i - 1)
b <- fibs(i - 2)
} yield a + b).value
}
This produces the same expected result.
Related
I am learning Scala apply and higher order function. I have this coding, but why compiler gave me an error: "missing parameter type", how to fix it ?
import scala.collection.mutable.ListBuffer
object MyArr {
var mList1 = ListBuffer[Int]()
def filter(p: Int => Boolean): List[Int] = {
val mList = List[Int]()
for (x <- mList1) {
if (p(x)) x :: mList
}
mList
}
def apply(x: Array[Int]) = {
for (y <- x) mList1 += y
}
}
def isEven(x: Int): Boolean = {
x % 2 == 0
}
var mCustomArr = MyArr(Array(1, 2, 3, 4))
mCustomArr.filter(x => isEven(x)).foreach(println)
if apply method just takes a single parameter and add it to mList1 , it will work. why ?
thanks
If you had added the return type to the apply() definition the compiler would have pointed out exactly where the error is.
def apply(x: Array[Int]): ListBuffer[Int] = {
for (y <- x) mList1 += y
mList1
}
In the apply method, it updates mList1 in Object and return Unit. So variable mCustomArr will be Unit type.
If you want to use filter method, you need to use MyArr Object like MyArr.filter(x => isEven(x)).foreach(println).
But when I look into your implementation of filter method, it looks like mList inside method never changed. I think the filter method could be implemented like
object MyArr {
var mList1 = ListBuffer[Int]()
def filter(p: Int => Boolean): ListBuffer[Int] = {
val mList = ListBuffer[Int]()
for (x <- mList1) {
if (p(x)) mList += x
}
mList
}
def apply(x: Array[Int]) = {
for (y <- x) mList1 += y
}
}
Hope you happy to learn Scala, Cheers.
I want to write some mergesort function.
How to supply Ordering[T] to merge subfunction?
The overall structure of application is the following:
object Main extends App {
...
val array: Array[Int] = string.split(' ').map(_.toInt)
def mergesort[T](seq: IndexedSeq[T]): IndexedSeq[T] = {
def mergesortWithIndexes(seq: IndexedSeq[T],
startIdx: Int, endIdx: Int): IndexedSeq[T] = {
import Helpers.append
val seqLength = endIdx - startIdx
val splitLength = seq.length / 2
val (xs, ys) = seq.splitAt(splitLength)
val sortXs = mergesortWithIndexes(xs, startIdx, startIdx + seqLength)
val sortYs = mergesortWithIndexes(ys, startIdx + seqLength, endIdx)
def merge(sortXs: IndexedSeq[T], sortYs: IndexedSeq[T],
writeFun: Iterable[CharSequence] => Path)(ord: math.Ordering[T]): IndexedSeq[T] = {
...
while (firstIndex < firstLength || secondIndex < secondLength) {
if (firstIndex == firstLength)
buffer ++ sortYs
else if (secondIndex == secondLength)
buffer ++ sortXs
else {
if (ord.lteq(minFirst, minSecond)) {
...
} else {
...
}
}
}
buffer.toIndexedSeq
}
merge(sortXs, sortYs, append(output))
}
mergesortWithIndexes(seq, 0, seq.length)
}
val outSeq = mergesort(array)
Helpers.write(output)(Vector(outSeq.mkString(" ")))
}
I want to have general merge() function definition, but in application I use IndexedSeq[Int] and thus expecting pass predefined Ordering[Int].
Adding implicit Ordering[T] parameter to the outermost function should fix the problem, and passing non Ordering[T] arguments will result in compile error.
Scala's sort functions do the same thing: https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/SeqLike.scala#L635
def mergesort[T](seq: IndexedSeq[T])(implicit ord: math.Ordering[T]): IndexedSeq[T] = {
Here is an example from the stairway book:
object Example1 {
import collection._
class PrefixMap[T]
extends mutable.Map[String, T]
with mutable.MapLike[String, T, PrefixMap[T]] {
var suffixes: immutable.Map[Char, PrefixMap[T]] = Map.empty
var value: Option[T] = None
def get(s: String): Option[T] = {
// base case, you are at the root
if (s.isEmpty) value
// recursive
else suffixes get (s(0)) flatMap (_.get(s substring 1))
}
def iterator: Iterator[(String, T)] = {
(for (v <- value.iterator) yield ("", v)) ++
(for ((chr, m) <- suffixes.iterator; (s, v) <- m.iterator) yield (chr +: s, v))
}
def +=(kv: (String, T)): this.type = {
update(kv._1, kv._2)
this
}
def -=(key: String): this.type = {
remove(key)
this
}
def withPrefix(s: String): PrefixMap[T] = {
if (s.isEmpty) this
else {
val leading = s(0)
suffixes get leading match {
case None => {
// key does not exist, create it
suffixes = suffixes + (leading -> empty)
}
case _ =>
}
// recursion
suffixes(leading) withPrefix (s substring 1)
}
}
override def update(s: String, elem: T) = {
withPrefix(s).value = Some(elem)
}
override def remove(key: String): Option[T] = {
if (key.isEmpty) {
// base case. you are at the root
val prev = value
value = None
prev
} else {
// recursive
suffixes get key(0) flatMap (_.remove(key substring 1))
}
}
override def empty = PrefixMap.empty
}
import collection.mutable.{Builder, MapBuilder}
import collection.generic.CanBuildFrom
object PrefixMap {
def empty[T] = new PrefixMap[T]
def apply[T](kvs: (String, T)*): PrefixMap[T] = {
val m: PrefixMap[T] = empty
for(kv <- kvs) m += kv
m
}
def newBuilder[T]: Builder[(String, T), PrefixMap[T]] = {
new mutable.MapBuilder[String, T, PrefixMap[T]](empty)
}
implicit def canBuildFrom[T]: CanBuildFrom[PrefixMap[_], (String, T), PrefixMap[T]] = {
new CanBuildFrom[PrefixMap[_], (String, T), PrefixMap[T]] {
def apply(from: PrefixMap[_]) = newBuilder[T]
def apply() = newBuilder[T]
}
}
}
}
I don't understand this line:
def apply(from: PrefixMap[_]) = newBuilder[T]
What's point in receiving a PrefixMap and returning a empty PrefixMap?
Read little bit more official docs
If in short: CBF can return builder with knowledge of properties of whole collection.
For example it could preinitialize some buffer of needed size to collect entries.
Or even reuse some parts of collection of known type and structure.
But by default in many case it would just collect element by element to empty collection. That's happening in your case.
Here is an example from the stairway book:
object Example1 {
import collection._
class PrefixMap[T]
extends mutable.Map[String, T]
with mutable.MapLike[String, T, PrefixMap[T]] {
var suffixes: immutable.Map[Char, PrefixMap[T]] = Map.empty
var value: Option[T] = None
def get(s: String): Option[T] = {
// base case, you are at the root
if (s.isEmpty) value
// recursive
else suffixes get (s(0)) flatMap (_.get(s substring 1))
}
def withPrefix(s: String): PrefixMap[T] = {
if (s.isEmpty) this
else {
val leading = s(0)
suffixes get leading match {
case None => {
// key does not exist, create it
suffixes = suffixes + (leading -> empty)
}
case _ =>
}
// recursion
suffixes(leading) withPrefix (s substring 1)
}
}
override def update(s: String, elem: T) = {
withPrefix(s).value = Some(elem)
}
override def remove(key: String): Option[T] = {
if (key.isEmpty) {
// base case. you are at the root
val prev = value
value = None
prev
} else {
// recursive
suffixes get key(0) flatMap (_.remove(key substring 1))
}
}
def iterator: Iterator[(String, T)] = {
(for (v <- value.iterator) yield ("", v)) ++
(for ((chr, m) <- suffixes.iterator; (s, v) <- m.iterator) yield (chr +: s, v))
}
def +=(kv: (String, T)): this.type = {
update(kv._1, kv._2)
this
}
def -=(key: String): this.type = {
remove(key)
this
}
override def empty = new PrefixMap[T]
}
}
Note that for the methods += and -=, the return types are this.type. Can I use PrefixMap[T] here? If yes, what does this.type has to offer?
Can I use PrefixMap[T] here?
Yes.
If yes, what does this.type has to offer?
For example, imagine you also have another class PrefixMap2[T] extending PrefixMap. Then with this.type, += and -= called on a PrefixMap2 will return itself (and therefore, a PrefixMap2); with PrefixMap return type, the compiler will only know they return a PrefixMap.
I had a simple task to find combination which occurs most often when we drop 4 cubic dices an remove one with least points.
So, the question is: are there any Scala core classes to generate streams of cartesian products in Scala? When not - how to implement it in the most simple and effective way?
Here is the code and comparison with naive implementation in Scala:
object D extends App {
def dropLowest(a: List[Int]) = {
a diff List(a.min)
}
def cartesian(to: Int, times: Int): Stream[List[Int]] = {
def stream(x: List[Int]): Stream[List[Int]] = {
if (hasNext(x)) x #:: stream(next(x)) else Stream(x)
}
def hasNext(x: List[Int]) = x.exists(n => n < to)
def next(x: List[Int]) = {
def add(current: List[Int]): List[Int] = {
if (current.head == to) 1 :: add(current.tail) else current.head + 1 :: current.tail // here is a possible bug when we get maximal value, don't reuse this method
}
add(x.reverse).reverse
}
stream(Range(0, times).map(t => 1).toList)
}
def getResult(list: Stream[List[Int]]) = {
list.map(t => dropLowest(t).sum).groupBy(t => t).map(t => (t._1, t._2.size)).toMap
}
val list1 = cartesian(6, 4)
val list = for (i <- Range(1, 7); j <- Range(1,7); k <- Range(1, 7); l <- Range(1, 7)) yield List(i, j, k, l)
println(getResult(list1))
println(getResult(list.toStream) equals getResult(list1))
}
Thanks in advance
I think you can simplify your code by using flatMap :
val stream = (1 to 6).toStream
def cartesian(times: Int): Stream[Seq[Int]] = {
if (times == 0) {
Stream(Seq())
} else {
stream.flatMap { i => cartesian(times - 1).map(i +: _) }
}
}
Maybe a little bit more efficient (memory-wise) would be using Iterators instead:
val pool = (1 to 6)
def cartesian(times: Int): Iterator[Seq[Int]] = {
if (times == 0) {
Iterator(Seq())
} else {
pool.iterator.flatMap { i => cartesian(times - 1).map(i +: _) }
}
}
or even more concise by replacing the recursive calls by a fold :
def cartesian[A](list: Seq[Seq[A]]): Iterator[Seq[A]] =
list.foldLeft(Iterator(Seq[A]())) {
case (acc, l) => acc.flatMap(i => l.map(_ +: i))
}
and then:
cartesian(Seq.fill(4)(1 to 6)).map(dropLowest).toSeq.groupBy(i => i.sorted).mapValues(_.size).toSeq.sortBy(_._2).foreach(println)
(Note that you cannot use groupBy on Iterators, so Streams or even Lists are the way to go whatever to be; above code still valid since toSeq on an Iterator actually returns a lazy Stream).
If you are considering stats on the sums of dice instead of combinations, you can update the dropLowest fonction :
def dropLowest(l: Seq[Int]) = l.sum - l.min