How is my attempt at implementing Functional Programming in Scala's below exercise?
// EXERCISE 5: Write a monoid instance for that String inserts spaces
// between words unless there already is one, and trims spaces off the ends of the
// result.
def trimMonoid = new Monoid[String] {
def op(a1: String, a2: String) = a1.trim + " " + a2.trim
val zero = ""
}
Is this the proper way to test the monoid? Here's the function signature, but I'm not sure how to implement with what I have: def trimMonoid(s: String): Monoid[String].
object MonoidTesting {
def main(args: Array[String]) = {
val words = List("Hic", "Est", "Barbarus")
val res = trimMonoid.op( ("Hic"), (trimMonoid.op("est ", "chorda ")) )
println("res : " + res)
assert(res == "Hic est chorda")
println("success")
}
}
One of the use cases of Monoid is in fold. I guess in Scala you have foldLeft and foldRight that you can use to test it on the list of string
val res = words.foldLeft(trimMonoid.zero)(trimMonoid.op _)
I am not sure if your trimMonoid does correctly what the exercise asks for, but anyways if its for testing then you could test it better this way:
scala> val xs = List("hey","hi","hello")
xs: List[String] = List(hey, hi, hello)
scala> xs.foldLeft(trimMonoid.zero)((x,y)=> trimMonoid.op(x,y))
res2: String = hey hi hello
Related
Assume I have
val x = List("a","b","c")
I'd like to have a function f which when called, returns
List("a","b","c")
Currently, println(x) just prints List(a,b,c) which will not compile when compiled/pasted into an Scala-Notebook or Unit-Test.
I'm stuck to find a general solution which also works for Seq[Double] etc , I managed to get something for Seq[String] by re-adding the quotes, but I'm unable to get a proper solution for all collection types
Sounds like you want custom type class Show
trait Show[T] {
def show(t: T): String
}
trait LowPriorityShow {
implicit def default[T]: Show[T] = _.toString
}
object Show extends LowPriorityShow {
implicit val str: Show[String] = s => s""""$s""""
// other exceptions for element types
implicit def list[T: Show]: Show[List[T]] = _.map(show(_)).mkString("List(", ",", ")")
implicit def seq[T: Show]: Show[Seq[T]] = _.map(show(_)).mkString("Seq(", ",", ")")
// other exceptions for collection types
}
def show[T](t: T)(implicit s: Show[T]): String = s.show(t)
val x = List("a","b","c")
show(x) //List("a","b","c")
val x1 = Seq("a","b","c")
show(x1) //Seq("a","b","c")
You can try to replace instances for collections (Show.list, Show.seq...) with more generic
import shapeless.Typeable
implicit def collection[Col[X] <: Iterable[X], T: Show](implicit ev: Typeable[Col[_]]): Show[Col[T]] = {
val col = Typeable[Col[_]].describe.takeWhile(_ != '[')
_.map(show(_)).mkString(s"$col(", ",", ")")
}
You'll have to check yourself whether the result is always a valid code in Scala.
I need to concatenate strings present inside a WrappedArray in Scala. I am able to do it with the help of List but that is not what I have to do. I want a solution specifically designed for WrappedArray and with scope of adding/deleting elements while concatenating. I have to use this function as a udf for transforming data via Spark SQL collect_list. That is why I am forced to use WrappedArray.
For e.g ->
WrappedArray("I","love","coding")
Output : String = I : love : coding
This is just an example like adding a colon. I am facing various type issues while matching in case of Wrapped Array.
import scala.annotation.tailrec
object tailRecursionString {
def getString(ints :scala.collection.mutable.WrappedArray[String]): String = {
#tailrec
def sumAccumulator(ints: scala.collection.mutable.WrappedArray[String], accum: String): String = {
ints match {
case Nil : => accum
case x :: tail => sumAccumulator(tail, accum + x)
}
}
sumAccumulator(ints, "[") + "]"
}
def main(args: Array[String]): Unit = {
val list : scala.collection.mutable.WrappedArray[String] = Array("kumar","sambhav","is","a","good","boy")
val sum = getString(list)
println(sum)
}
}
The reason of your problems is using WrappedArray which hasn't unapply method. Pattern matching works using unapply method, you can read more about this in scala documentation. Just replace WrappedArray to Array and matching expressions then it should works:
#tailrec
def sumAccumulator(ints: Array[String], accum: String): String = {
ints match {
case Array() => accum
case _ => sumAccumulator(ints.tail, accum + ints.head)
}
}
List has subtypes :: and Nil. They are case classes and case classes have unapply method generated by compiler.
Shortly, I try to describe how it works:
When compiler looking for extracting (in pattern matching) it looks at ::, sees that it's a subtype of List and has unapply method, and if unapply returns correct result it's choose this branch. The same way for Nil.
You could write it for Seq in general :
import scala.annotation.tailrec
def getString(ints :Seq[String]): String = {
#tailrec
def sumAccumulator(ints: Seq[String], accum: String): String = {
ints match {
case Seq(x) => accum
case Seq(x, xs#_*) => sumAccumulator(xs, accum + x)
}
}
sumAccumulator(ints, "[") + "]"
}
As WrappedArray is also a Seq, this will work
val seperator = " "
s"[${scala.collection.mutable.WrappedArray("I", "love", "coding").mkString(seperator)}]"
In case if you want to apply a filter, you can still use filter, and achieve the same.
<script src="https://scastie.scala-lang.org/lttp77S4Sout7VWkOXTEhQ.js"></script>
I have a list and two strings :
val features = List("one","two","three")
val strOne = "one_five"
val strTwo = "seven_five"
I'd like to match each string to items of the list.
If beginning of string matches one of list items then print matched list item and string itself.
If not, nothing to print.
I have method that I think make what I need but I cannot compile it :
def getElement(any: String): String = any match {
case s :: rest if features.contains(s) => s + "= " + any
case _ => // Nothing
}
I wanted the following :
scala> getElement(strOne)
"one_five= one"
scala> getElement(strTwo)
You can't just return nothing. You promised that your method would return a String, so you must return one. You can either return an Option[String] (preferred) or return Unit and do the printing yourself. Further, the built in method TraversableLike#find will do part of the job.
def findFeature(str: String): Option[String] = features.find(_ startsWith str) map { value => s"$str=$value" }
In order to get the printing behavior:
findFeature(str) foreach println
// or redefine findFeature similarly
Further, you seem to misunderstand pattern matching: You don't want to match on the string; you want to match the list's elements against the string. Here's a version that uses pattern matching:
def getElement(feature: String): Option[String] = {
#tailrec def getElem0(feature: String, strs: List[String]): Option[String] = strs match {
case s :: _ if s startsWith feature => Some(s"$feature=$s") // Matching case
case _ :: rest => getElem0(feature, rest) // Not matched, but more to search
case Nil => None // Empty list; failure
}
getElem0(feature, features)
}
Your solution can't compile because :: is a List method, and s is a String. Moreover, getElement is declared to return a String therefore it should return a String for any input. So you can't just return "nothing" in the second case.
Here's an alternative implementation:
def printElement(any: String): Unit = features
.find(s => any.startsWith(s)) // find matching (returns Option[String])
.foreach(s => println(s + "= "+ any)) // print if found
printElement(strOne) // one= one_five
printElement(strTwo)
Simple one line Scala code
Find in list the item who's first part is present in the list
features.find(_ == str.split("_")(0)).map { elem => s"$str= $elem"}.getOrElse("")
Put the above line inside the function.
def getElement(str: String): String = features.find(_ == str.split("_")(0)).map { elem => s"$str= $elem"}.getOrElse("")
Scala REPL
scala> val strOne = "one_five"
strOne: String = one_five
scala> val str = "one_five"
str: String = one_five
scala> features.find(_ == str.split("_")(0)).getOrElse("")
res2: String = one
scala> features.find(_ == str.split("_")(0)).map(elem => s"$str= $elem").getOrElse("")
res3: String = one_five= one
i have this very small requirement for learning purposes.
suppose we have the following string
"1.1 This is a test 34"
where
"1.1" is the chapter
"This is a test" is the title of the chapter
"34" is the page number
The overall result should give me some indication whether or not "parsed" line is ok.
Right now its only working for "well formed" lines (this is on purpose).
So far i have 2 ways of solving this...
1) Monad approach (though im not entirely sure this is done right, therefore my question)
trait Mine[A] {
def get(): A
def map(f: A => A): Mine[A]
def flatMap(f: A => Mine[A]): Mine[A]
}
case class Attempt1[A, B](a: (A, B)) extends Mine[(A, B)] {
def get(): (A, B) = a
def map(f: ((A, B)) => (A, B)): Mine[(A, B)] = {
Attempt1(f(a._1, a._2))
}
def flatMap(f: ((A, B)) => Mine[(A, B)]): Mine[(A, B)] = {
f(a._1, a._2)
}
}
and i also have following functions for getting text out of my "string" line
def getChapter2(t: (Result, String)): Mine[(Result, String)] = {
val result = t._1
val state = t._2
result.chapter = state.substring(0, 3)
var newState = state.substring(3)
Attempt1((result, newState))
}
def getTitle2(t: (Result, String)): Mine[(Result, String)] = {
val result = t._1
val state = t._2
result.title = state.substring(0, state.length() - 2)
var newState = state.substring(state.length() - 2)
Attempt1((result, newState))
}
def getPage2(t: (Result, String)): Mine[(Result, String)] = {
val result = t._1
val state = t._2
result.page = state
Attempt1((result, ""))
}
I can think of trying to use a higher order function for code that gets values "out" of Tuple2 and creation of Attempt1 stuff, but right now i want to keep things simple, the important thing for me is the monad stuff.
And finally this is the main logic.
var line = "1.1 Some awesome book 12"
val result = new Result("", "", "")
val at1 = Attempt1((result, line))
val r = for (
o1 <- at1;
o2 <- getChapter2(o1);
o3 <- getTitle2(o2);
o4 <- getPage2(o3)
) yield (o4)
val res = r.get._1
println("chapter " + res.chapter) //1.1
println("title " + res.title) // Some awesome book
println("page " + res.page) // 12
2) Compositional approach
def getChapter(t: (Result, String)): (Result, String) = {
val result = t._1
val state = t._2
result.chapter = state.substring(0, 3)
var newState = state.substring(3)
(result, newState)
}
def getTitle(t: (Result, String)): (Result, String) = {
val result = t._1
val state = t._2
result.title = state.substring(0, state.length() - 2)
var newState = state.substring(state.length() - 2)
(result, newState)
}
def getPage(t: (Result, String)): (Result, String) = {
val result = t._1
val state = t._2
result.page = state
(result, "")
}
as u can see functions are the same except on the return type (not "wrapped" by a Mine type), and i also have this method
def process(s: String, f: ((Result, String)) => (Result, String)): Result = {
val res = new Result("", "", "")
val t = f(res, s)
res
}
and my main logic is as follows
var line = "1.1 Some awesome book 12"
var fx = getChapter _ andThen getTitle _ andThen getPage
var resx = process(line, fx)
printf("title: %s%nchapter: %s%npage: %s%n", resx.title, resx.chapter, resx.page)
returnes values are the same as the "Monad approach".
So finally the questions would be:
Is "Monad approach" really a Monad??
I find compositional approach logic easier, and for this particular case Monad approach might seem overkill but remember this is for learning purposes.
I find that in both approaches logic flow is easy to reason.
If needed in both cases is easy to add or even remove a step in order to parse a string line.
I know this code is so similar and has room for improvement but right now im keeping it simple and maybe in the future i will factor commong things out.
Suggestions are welcome.
First off there is no need for the vars in your code. Second, since you are using substring function of a string, all you need is one partial function which takes the offsets of the sub-strings. This would be a good place to start when refactoring and would allow varied functionality for how you split the lines should the format change.
This would look like
def splitline(method:String)(symbol:String)(s:String) = method match {
case "substring" => val symb = Integer.parseInt(symbol) ;(s.substring(0,symb),s.substring(symb))
}
val getTitle = splitline("substring")("3") _
In terms of composition or monadic code, this falls on preference and the cognitive
load you wish to place on yourself.
Is there any way to create a PartialFunction except through the case statement?
I'm curious, because I'd like to express the following (scala pseudo ahead!)...
val bi = BigInt(_)
if (bi.isValidInt) bi.intValue
... as a partial function, and doing
val toInt : PartialFunction[String, Int] = {
case s if BigInt(s).isValidInt => BigInt(s).intValue
}
seems redundant since I create a BigInt twice.
Not sure I understand the question. But here's my attempt: Why not create an extractor?
object ValidBigInt {
def unapply(s: String): Option[Int] = {
val bi = BigInt(s)
if (bi.isValidInt) Some(bi.intValue) else None
}
}
val toInt: PartialFunction[String, Int] = {
case ValidBigInt(i) => i
}
The other option is (and that may answer the question as to whether one can create PartialFunction other than with a case literal):
val toInt = new PartialFunction[String, Int] {
def isDefinedAt(s: String) = BigInt(s).isValidInt
def apply(s: String) = BigInt(s).intValue
}
However since the idea of a partial function is that it's only partially defined, in the end you will still do redundant things -- you need to create a big int to test whether it's valid, and then in the function application you create the big int again...
I saw a project at Github that tried to come around this by somewhat caching the results from isDefinedAt. If you go down to the benchmarks, you'll see that it turned out to be slower than the default Scala implementation :)
So if you want to get around the double nature of isDefinedAt versus apply, you should just go straight for a (full) function that provides an Option[Int] as result.
I think you're looking for lift/unlift. lift takes a partial function and turns it into a function that returns an Option. Unlift takes a function with one argument that returns an option, and returns a partial function.
import scala.util.control.Exception._
scala> def fn(s: String) = catching(classOf[NumberFormatException]) opt {BigInt(s)}
fn: (s: String)Option[scala.math.BigInt]
scala> val fnPf = Function.unlift(fn)
fnPf: PartialFunction[String,scala.math.BigInt] = <function1>
scala> val fn = fnPf.lift
fn: String => Option[scala.math.BigInt] = <function1>
Closely related, you also want to look at this answer for information about cond and condOpt:
scala> import PartialFunction._
import PartialFunction._
scala> cond("abc") { case "def" => true }
res0: Boolean = false
scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
You can write out a PartialFunction "longhand" if you'd like:
object pf extends PartialFunction[Int,String] {
def isDefinedAt(in: Int) = in % 2 == 0
def apply(in: Int) = {
if (in % 2 == 0)
"even"
else
throw new MatchError(in + " is odd")
}
Okay, I got this
import java.lang.NumberFormatException
import scala.util.control.Exception._
val toInt: PartialFunction[String, Int] = {
catching(classOf[NumberFormatException]) opt BigInt(_) match {
case Some(bi) if bi.isValidInt => bi.intValue
}
}
How about this?
val toInt: PartialFunction[String, Int] = (s: String) => BigInt(s) match {
case bi if bi.isValidInt => bi.intValue
}