I have two functions, that I am trying to compose it:
private def convert(value: String)
: Path = decode[Path](value) match {
private def verify(parsed: Path)
: Path = parsed.os match {
I've tried as following:
verify compose convert _
The compiler complains:
[error] Unapplied methods are only converted to functions when a function type is expected.
[error] You can make this conversion explicit by writing `verify _` or `verify(_)` instead of `verify`.
[error] verify compose convert _
[error] ^
[error] one error found
I am trying to accomplish the following:
def process(value: String)
: Path =
verify(convert(value))
What am I doing wrong?
The problem is not everything in scala is a function. convert and verify in your example are methods not functions.
1) If you want to compose functions, define as functions as example below,
functions,
scala> def convert: String => String = (value: String) => "converted"
convert: String => String
scala> def verify = (value: String) => if(value == "converted") "valid" else "invalid"
verify: String => String
compose fns
scala> def vc = verify compose convert
vc: String => String
apply fn composition to functor
scala> Some("my-data").map{ vc.apply }
res29: Option[String] = Some(valid)
2) The another way is convert your existing methods to functions as below,
scala> def vc = (verify _ compose (convert _))
vc: String => String
scala> Some("data to convert").map { vc.apply }
res36: Option[String] = Some(valid)
References
https://twitter.github.io/scala_school/pattern-matching-and-functional-composition.html
Chapter 21 - Functions/Function literals
Function composition of methods, functions, and partially applied functions in Scala
Related
When I define this function, I can call it without a problem:
scala> val c = (_: String) + "sd"
c: String => String = <function1>
scala> c("1")
res13: String = 1sd
However if I let the above function print the result without returning it, I have the following error:
scala> val b = print((_: String) + "sd")
<function1>b: Unit = ()
scala> b("1")
<console>:26: error: Unit does not take parameters
b("1")
^
I know the system method print returns Unit type, but shouldn't the function b be a function that can be called with an argument as I defined? Why the above b function can not be called with b("1")?
How to understand and solve the problem? Thank you.
Indeed, as you have already discovered
print((_: String) + "sd")
expands to
print((x: String) => x + "sd")
instead of the desired
(x: String) => print(x + "sd")
because _ binds to the innermost expression delimiter () or {}.
Consider the following sequence.
An anonymous function from String to String.
scala> (_: String) + "sd"
res0: String => String = $$Lambda$1156/0x00000008406c1040#6b8bdcc6
Print the String representation of the anonymous function.
scala> println((_: String) + "sd")
$line10.$read$$iw$$iw$$$Lambda$1158/0x00000008406c3040#31f5b923
Print the String representation of the anonymous function. Save the result in variable b.
scala> val b = println((_: String) + "sd")
$line11.$read$$iw$$iw$$$Lambda$1159/0x00000008406a7040#173cfb01
b: Unit = ()
The print() and println() passed parameter is call-by-reference, not call-by-name, so it is fully evaluated at the call site before being passed to print(). In this case print() receives a function, it doesn't become part of a larger function.
my code as follow:
var args = "arg1,arg2" //come from external and also many e.g. arg3,arg4 ...
df.select(args.split(","):_*)
then got the errors:
:31: error: no `: *' annotation allowed here (such
annotations are only allowed in arguments to *-parameters)
df.select(args.split(","):*)
any body could give help? thanks.
Well... the use of varargs syntax (: _*) is allowed only for functions which expect variable arguments.
scala> def iAcceptVarArgs(strings: String*) = println(strings)
// iAcceptVarArgs: (strings: String*)Unit
scala> iAcceptVarArgs("str1", "str2")
// WrappedArray(str1, str2)
scala> iAcceptVarArgs(List("str1", "str2"): _*)
// List(str1, str2)
It will not work for functions which do not expect variable arguments,
scala> def iDoNotAcceptVarArgs(s: String) = println(List(s))
// iDoNotAcceptVarArgs: (s: String)Unit
scala> iDoNotAcceptVarArgs(List("str1"): _*)
// <console>:14: error: no `: _*' annotation allowed here
// (such annotations are only allowed in arguments to *-parameters)
// iDoNotAcceptVarArgs(List("str1"): _*)
^
Since Dataframe.select has following signature,
def select(col: String, cols: String*): DataFrame
It means that the first argument is fixed and only second argument onwards can be varargs
You should use pattern-matching in this case,
val args = "arg1,arg2"
val dfSelection = args.split(",").toList match {
case a1 :: tail => df.select(a1, tail: _*)
case Nil => df // well... what to do here ?
}
can you try this
var args = "arg1,arg2" //come from external and also many e.g. arg3,arg4 ...
var x = args.split(",").toList;
df.select(x.head,x.tail:_*)
I'm trying to invoke a function using the scala reflection api in v2.11.6:
import scala.reflect.runtime.{universe => ru}
def f(i: Int) = i + 2
val fn: Any = (f _)
val ref = ru.runtimeMirror(ru.getClass.getClassLoader).reflect(fn)
val apply = ref.symbol.typeSignature.member(ru.TermName("apply"))
When using ref.reflectMethod(apply.asMethod) it complains about multiple alternatives to apply on ref. Examining apply.asTerm.alternatives reveals two methods, one with signature (x$1: Int)Int and the other with (v1: T1)R. Calling
ref.reflectMethod(apply.asTerm.alternatives(1).asInstanceOf[ru.MethodSymbol])(1)
(with the second alternative) returns the correct result (3). However calling the first alternative raises an exception: java.lang.IllegalArgumentException: object is not an instance of declaring class
What are those alternatives and how can I make sure to always invoke the proper one? There also seems to be a problem with invoking a Function2 or higher with this method, so what is the correct way to do it?
The reason why there are overloaded apply methods is that Function1 is #specialized for primitive types.
I don't know if there is a better way to distinguish them, but the following seems to work, looking for the alternative whose argument erases to AnyRef (instead of a primitive such as Int):
def invoke(fun1: Any, arg1: Any): Any = {
import scala.reflect.runtime.{universe => ru}
val mirror = ru.runtimeMirror(ru.getClass.getClassLoader)
val ref = mirror.reflect(fn)
val applies = ref.symbol.typeSignature.member(ru.TermName("apply"))
val syms = apply.alternatives.map(_.asMethod)
val sym = syms.find { m =>
m.paramLists match {
case (arg :: Nil) :: Nil
if arg.asTerm.typeSignature.erasure =:= ru.typeOf[AnyRef] => true
case _ => false
}
} getOrElse sys.error("No generic apply method found")
ref.reflectMethod(sym)(arg1)
}
// Test:
val fn: Any = (i: Int) => i + 2
invoke(fn, 1) // res: 3
Inspired by this, I was wondering if we can have type-safe string interpolations in Scala (maybe using macros)?
For example, I want to have something like this
def a[A] = ???
val greetFormat = f"Hi! My name is ${a[String]}. I am ${a[Int]} years old"
greetFormat.format("Rick", 27) // compiles
//greetFormat.format("Rick", false) // does not compile
//greetFormat.format(27, "Rick") // does not compile
//greetFormat.format("Rick", 27, false) // does not compile
//greetFormat.format("Rick") // does not compile or is curried?
The f string interpolator is already implemented with a macro.
This can be demonstrated inside of the REPL:
scala> val b = "not a number"
b: String = not a number
scala> f"$b%02d"
<console>:9: error: type mismatch;
found : String
required: Int
f"$b%02d"
^
Just wrap it in a function.
def greet(name: String, age: Int) = s"Hi! My name is $name. I am $age years old"
You can supply implicits to the f-interpolator:
scala> case class A(i: Int)
defined class A
scala> implicit def atoi(a: A): Int = a.i
warning: there were 1 feature warning(s); re-run with -feature for details
atoi: (a: A)Int
scala> f"${A(42)}%02d"
res5: String = 42
See also Travis Brown's examples and solution for using regex group names in extractions. It took me about a minute to steal that great idea.
"a123bc" match {
case res # xr"(?<c>a)(?<n>\d+)(?<s>bc)" => assert {
res.c == 'a' && res.n == 123 && res.s == "bc"
}
}
For the record, on the composition side, I would like:
val a = A(Rick, 42)
val greeter = f"Hi! My name is $_. I am ${_}%d years old"
greeter(a, a)
But it was deemed too much for the poor underscore. You'll have to write the function as in the other answer.
Your form, in which your macro sees "${a[Int]}" and writes a function with an Int param, doesn't look hard to implement.
Other features of the f-interpolator include other static error checking:
scala> f"$b%.02d"
<console>:19: error: precision not allowed
f"$b%.02d"
^
and support for Formattable:
scala> val ff = new Formattable { def formatTo(fmtr: Formatter, flags: Int, width: Int, precision: Int) = fmtr.format("%s","hello, world") }
ff: java.util.Formattable = $anon$1#d2e6b0b
scala> f"$ff"
res6: String = hello, world
A quick macro might emit (i: Int) => f"${ new Formattable {...} }".
It does not look very good for me to always repeat a line-long tuple definition every time I need it. Can I just name it and use as a type name? Would be nice to name its fields also instead of using ._1, ._2 etc.
Regarding your first question, you can simply use a type alias:
type KeyValue = (Int, String)
And, of course, Scala is an object-oriented language, so regarding your second about how to specialize a tuple, the magic word is inheritance:
case class KeyValue(key: Int, value: String) extends (Int, String)(key, value)
That's it. The class doesn't even need a body.
val kvp = KeyValue(42, "Hello")
kvp._1 // => res0: Int = 42
kvp.value // => res1: String = "Hello"
Note, however, that inheriting from case classes (which Tuple2 is), is deprecated and may be disallowed in the future. Here's the compiler warning you get for the above class definition:
warning: case class class KV has case class ancestor class Tuple2. This has been deprecated for unduly complicating both usage and implementation. You should instead use extractors for pattern matching on non-leaf nodes.
Type alias is fine for naming your Tuple, but try using a case class instead. You will be able to use named parameters
Example with tuple:
def foo(a : Int) : (Int, String) = {
(a,"bar")
}
val res = foo(1)
val size = res._1
val name= res._2
With a case class:
case class Result( size : Int , name : String )
def foo(a : Int) : Result = {
Result(a,"bar")
}
val res = foo(1)
val size = res.size
val name= res.name
Here's a solution that creates a type alias and a factory object.
scala> type T = (Int, String)
defined type alias T
scala> object T { def apply(i: Int, s: String): T = (i, s) }
defined module T
scala> new T(1, "a")
res0: (Int, String) = (1,a)
scala> T(1, "a")
res1: (Int, String) = (1,a)
However as others have mentioned, you probably should just create a case class.
Although as others have said, explicit (case) classes are best in the general sense.
However for localized scenarios what you can do is to use the tuple extractor to improve code readability:
val (first, second) = incrementPair(3, 4)
println(s"$first ... $second")
Given a method returning a tuple:
def incrementPair(pair: (Int, Int)) : (Int, Int) = {
val (first, second) = pair
(first + 1, second + 1)
}