Formatting with an Option[String] in Scala - scala

I'm trying to find a concise way to format a String with an Option[String] in Scala. I have a title String and a subtitle Option[String]. Here's what I have but I feel like there has to be a better way:
"Title%s".format(subtitle match
{case Some(s) => ": %s".format(s)
case None => "" })
So if I have a subtitle, I want "Title: Subtitle", but if subtitle is None, I just want "Title".

subtitle map (t => s"Title: $t") getOrElse ("Title")
String interpolation is more safe than format because if you don't use correct variable name, or missuse it somehow it will fail at compile time. format will fail at run time if the number of placeholders or their types do not match format arguments.
Your version of Scala must support this feature and have it enabled.

"Title%s".format(subtitle.map(": " + _).getOrElse(""))
map method is very convenient to use with the Option type. You can say what you want to do assuming some value is there, and don't care what happens if it's None. At the end you just provide an alternative if the latter occured (in our case empty String "").

A bit cleaner than your approach but the same idea. I think this is pretty readable:
"Title: %s" format subtitle.getOrElse("")
As an aside, the following link is a great resource if you're pattern matching on an Option but think there's probably a better way: Scala Option Cheat sheet

Well you could use:
"Title" + subtitle.fold("")(": " + _)
but personally I still find that a little verbose so I have a utilities package that I import which includes
implicit class OptionRichClass[A](n: Option[A])
{
def apply[T](valNone: T, fSome: A => T): T = n.fold(valNone)(s => fSome(s))
def mapList[T](f: (A) => T): List[T] = n.map[T](f(_)).toList
def flatList[T](f:(A) => List[T]): List[T] = n.fold(List[T]())(f(_))
def flatSeq[T](f:(A) => Seq[T]): Seq[T] = n.fold(Seq[T]())(f(_))
}
The apply method is the important one here which would allow me to write:
"Title" + subtitle("", ": " + _)

Related

Scala Pattern Matching using Option[Type]

I am playing around with Scala at the moment and the pattern matching. I have the general idea behind it and can get the basics working. My issue is with Option[]. It is possible to use pattern matching on Option[]'s?
What I am trying to do is make a little function that will take in an option[String] parameter and then based on the input return the string if its a string and a heads up if not. I am not too sure on how to go about this though, I have tried a few thing but it either gives out or in the case below will never hit the second case.
def getString(someString: Option[String]): String =
someString match {
case s: Option[String] => someString //also tried things like case: String => ...
case _ => s"no string entered" //and things like case _ => ...
}
This is the easiest way to implement your function:
def getString(someString: Option[String]): String =
someString.getOrElse("no string entered")
If you want to use match it looks like this:
def getString(someString: Option[String]): String =
someString match {
case Some(s) => s
case _ => "no string entered"
}

Idiomatic alternative to `if (x) Some(y) else None`

I'm finding the following pattern popping up repeatedly in my code, and my intuition says there must be some idiomatic Scala way to better express this (Monadic or otherwise):
val someCollection: Seq[Thing] = ...
val makeBlah: Seq[Thing] => Blah = ...
...
if (someCollection.nonEmpty) Some(makeBlah(someCollection)) else None
To be more specific, I'm looking for something along the lines of what you can do with Option[T]:
val someOption: Option[Thing] = ...
val makeBlah: Thing => Blah = ...
...
val result: Option[Blah] = someOption.map(makeBlah)
...but with evaluation semantics based on some predicate rather than Some/None pattern matching in map.
While the example above uses a collection--first performing a test on it, optionally followed by an operation--I don't mean to imply a collections specific use case. You could imagine a case where Boolean is lifted or coerced into some monad:
val aThing: Thing = ...
val makeBlah: Thing => Blah = ...
val thingTest: Thing => Boolean ...
// theoretical
implicit def optionOnBoolean(b: Boolean): MonadOps[Option[Boolean]] = ...
...
// NB: map could either have a Boolean parameter
// that's always true, or be Unit.
// Neither seem like good design
val result: Option[Blah] = thingTest(aThing).map(makeBlah(aThing))
Intuitively this seems like a bad idea to me because it explicitly splits the data flow since you don't really have anything to pass via map.
When looking for a general approach that has "monadic-like" behavior without a closure to capture data, one has to answer the question of what to pass to map and how its connection to the predicate. Here's the type of construct that comes to mind:
val thing: Thing = ....
val makeBlah: Thing => Blah = ...
val thingTest: (Thing) => Boolean = ...
val result: Option[Blah] = WhenOption(thing, thingTest).map(makeBlah)
My question: Does something already exist in Scala proper, or does one have to venture out to Scalaz to get this sort of construct?
Or is there some other approach that is customary/idiomatic Scala?
Edit: My question is close to Scala - "if(true) Some(1)" without having to type "else None" but I wish to address the issue of achieving it without a closure.
For completeness:
val someCollection: Seq[Thing] = ...
val makeBlah: Seq[Thing] => Blah = ...
You can use some methods on Option:
Some(someCollection).filterNot(_.isEmpty).map(makeBlah)
or as for comprehension
for(sc <- Some(someCollection) if !someCollection.isEmpty) yield makeBla(sc)
or as pattern match
someCollection match {
case Seq() => None
case x => Some(makeBlah(x))
}
But I think the if-then-else approach is the most readable one.
I would just continue doing what you're doing unless you find yourself repeating that same logic ad nauseum within the same function scope. It's readable and makes sense. That said, if you really need to, you can "lift" a PartialFunction (see here):
def foo: PartialFunction[Seq[A], B]
def fooLifted: (Seq[A] => Option[B]) = foo.lift
Now all you have to do is make your conditional logic explicit
def foo ={
case seq if predicate(seq) => doStuff(seq)
}
This is a lot more boilerplate than what you're doing.
FWIW, I do the same thing you propose:
implicit class RichBoolean(val b: Boolean) extends AnyVal {
def map[T](f: => T): Option[T] = if (b) Some(f) else None
def flatMap[T](f: => Option[T]): Option[T] = if (b) f else None
}
"map" doesn't feel right here, but I can't think of anything better. I really like this construct, it can really help keep the "flow" when doing a few consecutive operations on your data.

Scala: how to handle many params that can be None

Right now I have many params that can be none, and I want to assign the whole expressiona default value.
Right now I'm doing things like
var name: Option[String] = None
var surname: Option[String] = Some("Smith")
val fullName:String = {
name.map { name =>
surname.map { surname =>
surname + ", " + name
}.getOrElse("unknown")
}.getOrElse("unknown")
}
but it's a bit too verbose. I'd like to know what would be a more idiomatic and elegant way to handle it, ideally it would be something like (it's pseudo code, of course!):
val fullName = (name + ", " + surname).getOrElse("unknown")
or something similar...
(just avoiding the double .getOrElse would be great...)
How about this
scala> val fullName = (for(n <-name;s <-surname) yield n + s).getOrElse("unknown")
fullName: String = unknown
You might want to learn a bit about applicative functors, as the same pattern can be used in all sorts of ways. Using scalaz, there is the applicative builder:
(name |#| surname)(_ + _)
What is going on is this:
(M[A] |#| M[B])(fabc) ~> M[C] //fabc is a function f: (A, B) => C
That is, the function f is being lifted into the realm of applicative functor M. This is particularly useful because it works with Option, Validation, Promise, List, Stream and many more. That is, just as you might use the expression:
(name |#| surname)(_ + _)
where name and surname are both Option[String], you could switch them to be ValidationNEL[Exception, String] or Promise[String] and the code would still do the exact same thing (appropriate to the higher kind being used). This is very powerful.
I've found this way:
val fullname = (name, surname) match {
case (Some(x), Some(y)) => x + ", " + y
case _ => "unknonw"
}
but it's still a bit verbose

How to extract remainder of sequence in pattern matching

I've obviously done a very poor job of explaining what I'm looking for in my original post so let's try this one more time. What I'm trying to accomplish is the ability to pass a sequence of items, extract one or more of the items, and then pass the REMAINDER of the sequence on to another extractor. Note that by sequence I mean sequence (not necessarily a List). My previous examples used list as the sequence and I gave some examples of extraction using cons (::), but I could just as well pass an Array as my sequence.
I thought I knew how pattern matching and extraction worked but I could be wrong so to avoid any more basic comments and links to how to do pattern matching sites here's my understanding:
If I want to return a single item from my extractor I would define an unapply method. This method takes whatever type I chose as input (the type could be a sequence...) and returns a single optional item (the return type could itself be a sequence). The return must be wrapped in Some if I want a match or None if I don't. Here is an example that takes a sequence as input and returns the same sequence wrapped in Some but only if it contains all Strings. I could very well just return the sequence wrapped in Some and not do anything else, but this seems to cause confusion for people. The key is if it is wrapped in Some then it will match and if it is None it will not. Just to be more clear, the match will also not happen unless the input also matches my unapply methods input type. Here is my example:
object Test {
// In my original post I just returned the Seq itself just to verify I
// had matched but many people commented they didn't understand what I
// was trying to do so I've made it a bit more complicated (e.g. match
// only if the sequence is a sequence of Strings). Hopefully I don't
// screw this up and introduce a bug :)
def unapply[A](xs: Seq[A]): Option[Seq[String]] =
if (xs forall { _.isInstanceOf[String] })
Some(xs.asInstanceOf[Seq[String]])
else
None
}
Using List as an example, I can now perform the following:
// This works
def test1(xs: List[_]) = xs match {
case (s: String) :: Test(rest) =>
println("s = " + s + ", rest = " + rest)
case _ =>
println("no match")
}
test1(List("foo", "bar", "baz")) // "s = foo, rest = List(bar, baz)"
My test1 function takes List as input and extracts the head and tail using cons via the constructor pattern (e.g. ::(s, rest)). It then uses type ascription (: String) to make sure the head (s) is a String. The tail contains List("bar", "baz"). This is a List which means it is also a Seq (sequence). It is then passed as input to my Test extractor which verifies that both "bar" and "baz" are strings and returns the List wrapped in Some. Since Some is returned it is considered a match (although in my original post where I inadvertently mixed up unapplySeq with unapply this didn't work as expected, but that aside...). This is NOT what I'm looking for. This was only an example to show that Test does in fact extract a Seq as input as expected.
Now, here's where I caused mass confusion last time when I inadvertently used unapplySeq instead of unapply in my write up. After much confusion trying to understand the comments that were posted I finally picked up on the mistake. Many thanks to Dan for pointing me in the right direction...
But just be avoid any more confusion, let me clarify my understanding of unapplySeq. Like unapply, unapplySeq takes in whatever argument I choose as input, but instead of returning a single element it returns a sequence of elements. Each item in this sequence can then be used for additional pattern matching. Again, to make a match happen the input type must match and my returned sequence must be wrapped in Some and not be None. When extracting over the sequence of items returned from unapplySeq, you can use _* to match any remaining items not yet matched.
Ok, so my extractor takes a sequence as input and returns a sequence (as a single item) in return. Since I only want to return a single item as a match I need to use unapply NOT unapplySeq. Even though in my case I'm returning a Seq, I don't want unapplySeq because I don't want to do more pattern matching on the items in the Seq. I just want to return the items as a Seq on its own to then be passed to the body of my case match. This sounds confusing, but to those that understand unapply vs unapplySeq I hope it isn't.
So here is what I WANT to do. I want to take something that returns a sequence (e.g. List or Array) and I want to extract a few items from this sequence and then extract the REMAINDER of the items (e.g. _*) as a sequence. Let's call it the remainder sequence. I want to then pass the remainder sequence as input to my extractor. My extractor will then return the remaining items as a single Seq if it matches my criteria. Just to be 100% clear. The List (or Array, etc) will have its unapplySeq extractor called to create the sequence of items. I will extract a one or more of these items and then pass what is left as a sequence to my Test extractor which will use unapply (NOT unapplySeq) to return the remainder. If you are confused by this, then please don't comment...
Here are my tests:
// Doesn't compile. Is there a syntax for this?
def test2(xs: Seq[_]) = xs match {
// Variations tried:
// Test(rest) # _* - doesn't compile (this one seems reasonable to me)
// Test(rest # _*) - doesn't compile (would compile if Test had
// unapplySeq, but in that case would bind List's
// second element to Test as a Seq and then bind
// rest to that Seq (if all strings) - not what I'm
// looking for...). I though that this might work
// since Scala knows Test has no unapplySeq only
// unapply so # _* can be tied to the List not Test
// rest # Test(_*) - doesn't compile (didn't expect to)
case List(s: String, Test(rest) # _*) =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
// This works, but messy
def test3(xs: List[_]) = xs match {
case List(s: String, rest # _*) if (
rest match { case Test(rest) => true; case _ => false }
) =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
I created test3 based on comments from Julian (thanks Julian..). Some have commented that test3 does what I want so they are confused what I'm looking for. Yes, it accomplishes what I want to accomplish, but I'm not satisfied with it. Daniel's example also works (thanks Daniel), but I'm also not satisfied with having to create another extractor to split things and then do embedded extractions. These solutions seem too much work in order to accomplish something that seems fairly straight forward to me. What I WANT is to make test2 work or know that it can't be done this way. Is the error given because the syntax is wrong? I know that rest # _* will return a Seq, that can be verified here:
def test4(xs: List[_]) = xs match {
case List(s: String, rest # _*) =>
println(rest.getClass) // scala.collection.immutable.$colon$colon
case _ =>
println("no match")
}
It returns cons (::) which is a List which is a Seq. So how can I pass the _* Seq on to my extractor and have is return bound to the variable rest?
Note that I've also tried passing varargs to my unapply constructor (e.g. unapply(xs: A*)...) but that won't match either.
So, I hope it is clear now when I say I want to extract the remainder of a sequence in pattern matching. I'm not sure how else I can word it.
Based on the great feedback from Daniel I'm hoping he is going to have an answer for me :)
I'd like to extract the first item and pass the remainder on to another extractor.
OK. Your test1 does that, exactly. first_item :: Extractor(the_rest). The weird behavior you're seeing comes from your Test extractor. As you already had the answer to your stated question, and as expected behavior from your Test strikes you as a problem with test1, it seems that what you really want is some help with extractors.
So, please read Extractor Objects, from docs.scala-lang.org, and Pattern Matching in Scala (pdf). Although that PDF has an example of unapplySeq, and suggests where you'd want to use it, here are some extra examples:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
Interactively:
scala> List(1,2,3,4) match { case Sorted(xs) => Some(xs); case _ => None }
res0: Option[Seq[Int]] = Some(List(1, 2, 3, 4))
scala> List(4,1,2,3) match { case Sorted(xs) => Some(xs); case _ => None }
res1: Option[Seq[Int]] = None
scala> List(4,1,2,3) match { case first :: Sorted(rest) => Some(first, rest); case _ => None }
res2: Option[(Int, Seq[Int])] = Some((4,List(1, 2, 3)))
scala> List(1,2,3,4) match { case SortedSeq(a,b,c,d) => (a,b,c,d) }
res3: (Int, Int, Int, Int) = (1,2,3,4)
scala> List(4,1,2,3) match { case _ :: SortedSeq(a, b, _*) => (a,b) }
res4: (Int, Int) = (1,2)
scala> List(1,2,3,4) match { case SortedSeq(a, rest # _*) => (a, rest) }
res5: (Int, Seq[Int]) = (1,List(2, 3, 4))
Or maybe -- I only have the faint suspicion of this, you haven't said as much -- you don't want extractor help, but actually you want a terse way to express something like
scala> List(1,2,3,4) match { case 1 :: xs if (xs match { case Sorted(_) => true; case _ => false }) => xs }
res6: List[Int] = List(2, 3, 4)
Erlang has a feature like this (although, without these crazy extractors):
example(L=[1|_]) -> examine(L).
, which pattern-matches the same argument twice - to L and also to [1|_]. In Erlang both sides of the = are full-fledged patterns and could be anything, and you can add a third or more patterns with more =. Scala seems to only support the L=[1|_] form, having a variable and then a full pattern.
scala> List(4,1,2,3) match { case xs # _ :: Sorted(_) => xs }
collection.immutable.::[Int] = List(4, 1, 2, 3)
Well, the easiest way is this:
case (s: String) :: Test(rest # _*) =>
If you need this to work on general Seq, you can just define an extractor to split head from tail:
object Split {
def unapply[T](xs: Seq[T]): Option[(T, Seq[T])] = if (xs.nonEmpty) Some(xs.head -> xs.tail) else None
}
And then use it like
case Split(s: String, Test(rest # _*)) =>
Also note that if you had defined unapply instead of unapplySeq, then # _* would not be required on the pattern matched by Test.
:: is an extractor. For how it works (from a random googling), see, for example, here.
def test1(xs: List[_]) = xs match {
case s :: rest =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
scala> test1(List("a", "b", "c"))
s = a rest = List(b, c)
I think this is what you wanted?
Messing around with this, it seems that the issue has something to do with unapplySeq.
object Test {
def unapply[A](xs: List[A]): Option[List[A]] = Some(xs)
}
def test1(xs: List[_]) = xs match {
case (s: String) :: Test(s2 :: rest) =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
test1(List("foo", "bar", "baz"))
produces the output:
s = foo rest = List(baz)
I'm havng trouble googling up docs on the difference between unapply and unapplySeq.

Can extractors be customized with parameters in the body of a case statement (or anywhere else that an extractor would be used)?

Basically, I would like to be able to build a custom extractor without having to store it in a variable prior to using it.
This isn't a real example of how I would use it, it would more likely be used in the case of a regular expression or some other string pattern like construct, but hopefully it explains what I'm looking for:
def someExtractorBuilder(arg:Boolean) = new {
def unapply(s:String):Option[String] = if(arg) Some(s) else None
}
//I would like to be able to use something like this
val {someExtractorBuilder(true)}(result) = "test"
"test" match {case {someExtractorBuilder(true)}(result) => result }
//instead I would have to do this:
val customExtractor = someExtractorBuilder(true)
val customExtractor(result) = "test"
"test" match {case customExtractor(result) => result}
When just doing a single custom extractor it doesn't make much difference, but if you were building a large list of extractors for a case statement, it could make things more difficult to read by separating all of the extractors from their usage.
I expect that the answer is no you can't do this, but I thought I'd ask around first :D
Parameterising extractors would be cool, but we don't have the resources to implement them right now.
Nope.
8.1.7 Extractor Patterns
An extractor pattern x (p 1 , . . . ,
p n ) where n ≥ 0 is of the same
syntactic form as a constructor
pattern. However, instead of a case
class, the stable identifier x denotes
an object which has a member method
named unapply or unapplySeq that
matches the pattern.
One can customize extractors to certain extent using implicit parameters, like this:
object SomeExtractorBuilder {
def unapply(s: String)(implicit arg: Boolean): Option[String] = if (arg) Some(s) else None
}
implicit val arg: Boolean = true
"x" match {
case SomeExtractorBuilder(result) =>
result
}
Unfortunately this cannot be used when you want to use different variants in one match, as all case statements are in the same scope. Still, it can be useful sometimes.
Late but there is a scalac plugin in one of my lib providing syntax ~(extractorWith(param), bindings):
x match {
case ~(parametrizedExtractor(param)) =>
"no binding"
case ~(parametrizedExtractor(param), (a, b)) =>
s"extracted bindings: $a, $b"
}
https://github.com/cchantep/acolyte/blob/master/scalac-plugin/readme.md
Though what you are asking isn't directly possible,
it is possible to create an extractor returning a contaner that gets evaluated value in the if-part of the case evaluation. In the if part it is possible to provide parameters.
object DateExtractor {
def unapply(in: String): Option[DateExtractor] = Some(new DateExtractor(in));
}
class DateExtractor(input:String){
var value:LocalDate=null;
def apply():LocalDate = value;
def apply(format: String):Boolean={
val formater=DateTimeFormatter.ofPattern(format);
try{
val parsed=formater.parse(input, TemporalQueries.localDate());
value=parsed
true;
} catch {
case e:Throwable=>{
false
}
}
}
}
Usage:
object DateExtractorUsage{
def main(args: Array[String]): Unit = {
"2009-12-31" match {
case DateExtractor(ext) if(ext("dd-MM-yyyy"))=>{
println("Found dd-MM-yyyy date:"+ext())
}
case DateExtractor(ext) if(ext("yyyy-MM-dd"))=>{
println("Found yyyy-MM-dd date:"+ext())
}
case _=>{
println("Unable to parse date")
}
}
}
}
This pattern preserves the PartialFunction nature of the piece of code. I find this useful since I am quite a fan of the collect/collectFirst methods, which take a partial function as a parameter and typically does not leave room for precreating a set of extractors.