What is the difference between .() and .{} in Reason? - reason

I'm trying to figure out why the example for using Js.Promise uses
Js.Promise.(
...
)
Whereas the example for Json.Decode uses
Json.Decode.{
...
}
From what I understand, .() opens up Js.Promise so that I can just call any function within Js.Promise without having to prefix Js.Promise as the module.
But what does .{} do?

Both put some module declarations in scope, but .{} creates a record while .() wraps an expression.
For records:
let point = json =>
Json.Decode.{
x: json |> field("x", float),
y: json |> field("y", float)
};
is equivalent to:
let point = json =>
{
x: json |> Json.Decode.field("x", Json.Decode.float),
y: json |> Json.Decode.field("y", Json.Decode.float)
};
Similarly, for expressions:
let _ =
Js.Promise.(then_(value => resolve(Js.log(value)), okPromise));
is equivalent to:
let _ =
Js.Promise.then_(value => Js.Promise.resolve(Js.log(value)), okPromise));

Related

Pass function of function as parameter in Scala

I have a method setBuildQuery and I want that it can receive as parameter a function x. The function x should take as input an indefinite number of parameters and output another function y.
Function y takes as input two dates and outputs a string.
Examples using a function notation
x = (one_f)(from_date, to_date) => string or
x = (one_f, two_f)(from_date, to_date) => string or
x = (one_f, two_f, ..., n_f)(from_date, to_date) => string
How can I model this in Scala (i.e. how can I say to a function to accept a function x of this type?
How the user of my app can specify this function as a val ?
I was thinking something like function of function or high order functions. I am not too familiar with them in Scala though.
You can't have a function that takes an arbitrary number of parameters.* The best you could do is take a function that takes a Seq:
def setBuildQuery(f: Seq[YourType] => (Date, Date) => String)
You could then define a function it accepts like this:
val f: Seq[YourType] => (Date, Date) => String =
ls => (from, to) => ???
* You can have a method that takes an arbitrary number of parameters, but that doesn't help here.
There are many way to do that, you can use Partial Application to define your function.
The function will not execute until you invoke it with all its parameters
def x(head:String, tail:String*)(from:Date, to:Date): String = {
println(head) // it doesnt exec until from and to are provided
"result"
}
val y = x("string1", "string2") _
y(new Date, new Date)
or you can return a function
def x(head:String, tail:String*): (Date,Date) => String = {
println(head) // it exec before from and to are provided
(from:Date, to:Date) => {
"result"
}
}
val y = x("string1", "string2")
y(new Date, new Date)

Passing function arguments by Name Scala

I have the following scala code. In this code, I am passing a (global) string name to a function and want to change the string depending on the first argument as shown below:
def retVal(x: (String,String), y: => String) = {if (x._1 != "") {y = x._1;x} else (y,x._2)}
But when I run this code, I get the following error:
y = x._1
^
reassignment to a val
How can I modify the code, so that I get the global string variable get updated when I call this function?
Function arguments are by default immutable in Scala. You cannot assign the a value to the function parameter.
In your case you are trying to assign to a call by name param which is not at all possible.
Also mutating is bad instead return the value and assign it to a new variable.
But still if you want to mutate do something like this
object MutationBox {
var globalString = ""
def retVal(x: (String,String)) = {
if (x._1.nonEmpty) {
globalString = x._1
x
} else (globalString, x._2)
}
}

How do I implement a JavaScript-style callback?

I'm trying to implement a JavaScript-style callback. I have an application that uses a library (both are mine) and I need the application to be able to pass a closure or function to a method in the library, which then spawns a thread and inside the thread when a condition is met it will call the callback.
main.rs
fn main(){
welcome_message();
mylib::connect(|| println!("Connected to service! Please enter a command. (hint: help)\n\n"));
loop {
match prompt_input() {
true => {},
false => break,
}
}
}
lib.rs
pub fn connect<F>(resolve: F) -> (mpsc::Sender<Message>, mpsc::Receiver<Message>)
where F: Fn()
{
...
let receive_loop = Thread::scoped(move || {
for response in receiver.incoming_messages::<Message>(){
let json_string = match response.unwrap() {
Message::Text(txt) => txt,
_ => "".to_string(),
};
let message = json::Json::from_str(json_string.as_slice());
let message_json = message.unwrap();
if message_json.is_object() {
let ref something = receiver_tx;
let obj = message_json.as_object().unwrap();
let something_json = obj.get("lsri").unwrap();
let something = something_json.to_string().replace("\"", "");
match something.as_slice() {
"service#connected" => resolve(),
_ => println!("{}", type),
}
} else {
println!("Invalid service response");
}
}
});
...
}
Error
src/lib.rs:54:24: 54:38 error: the trait `core::marker::Send` is not implemented for the type `F` [E0277]
src/lib.rs:54 let receive_loop = Thread::scoped(move || {
^~~~~~~~~~~~~~
src/lib.rs:54:24: 54:38 note: `F` cannot be sent between threads safely
src/lib.rs:54 let receive_loop = Thread::scoped(move || {
^~~~~~~~~~~~~~
It doesn't need to be a closure that I pass, I could pass a function too. It doesn't need any arguments or return types, but I could add some dummy ones if that helps. I am VERY open to suggestions of other methods or ways to accomplish the same goal.
I have tried using:
Thread::spawn
FnMut()
Arc::new(resolve) (with implementation of .clone())
Arc::new(Mutex::new(resolve)) (with implementation of .lock())
Searching Google for examples
Reading the Rust book in it's entirety
Searching the error message for examples
All of the above in various configurations
Is this possible with Rust? Is there a better way?
Thank you for your time in advance.
Solution:
For anyone finding this in the future, per the instructions of the answer below I changed the signature of connect to the following, which allowed the callback to be passed into the thread.
pub fn connect<'a, T, F>(resolve: F) -> (mpsc::Sender<Message>, mpsc::Receiver<Message>)
where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
Try marking your F with the same restrictions as Thread::scoped:
fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T>
where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
specifically, bounding the type with the Send trait should clear the immediate error of
the trait core::marker::Send is not implemented for the type F

Specifying the lambda return type in Scala

Note: this is a theoretical question, I am not trying to fix anything, nor am I trying to achieve any effect for a practical purpose
When creating a lambda in Scala using the (arguments)=>expression syntax, can the return type be explicitly provided?
Lambdas are no different than methods on that they both are specified as expressions, but as far as I understand it, the return type of methods is defined easily with the def name(arguments): return type = expression syntax.
Consider this (illustrative) example:
def sequence(start: Int, next: Int=>Int): ()=>Int = {
var x: Int = start
//How can I denote that this function should return an integer?
() => {
var result: Int = x
x = next(x)
result
}
}
You can always declare the type of an expression by appending : and the type. So, for instance:
((x: Int) => x.toString): (Int => String)
This is useful if you, for instance, have a big complicated expression and you don't want to rely upon type inference to get the types straight.
{
if (foo(y)) x => Some(bar(x))
else x => None
}: (Int => Option[Bar])
// Without type ascription, need (x: Int)
But it's probably even clearer if you assign the result to a temporary variable with a specified type:
val fn: Int => Option[Bar] = {
if (foo(y)) x => Some(bar(x))
else _ => None
}
Let say you have this function:
def mulF(a: Int, b: Int): Long = {
a.toLong * b
}
The same function can be written as lambda with defined input and output types:
val mulLambda: (Int, Int) => Long = (x: Int, y: Int) => { x.toLong * y }
x => x:SomeType
Did not know the answer myself as I never had the need for it, but my gut feeling was that this will work. And trying it in a worksheet confirmed it.
Edit: I provided this answer before there was an example above. It is true that this is not needed in the concrete example. But in rare cases where you'd need it, the syntax I showed will work.

Scala: parsing an API parameter

My API currently take an optional parameter named gamedate. It is passed in as a string at which time I later parse it to a Date object using some utility code. The code looks like this:
val gdate:Option[String] = params.get("gamedate")
val res = gdate match {
case Some(s) => {
val date:Option[DateTime] = gdate map { MyDateTime.parseDate _ }
val dateOrDefault:DateTime = date.getOrElse((new DateTime).withTime(0, 0, 0, 0))
NBAScoreboard.findByDate(dateOrDefault)
}
case None => NBAScoreboard.getToday
}
This works just fine. Now what I'm trying to solve is I'm allowing multiple gamedates get passed in via a comma delimited list. Originally you can pass a parameter like this:
gamedate=20131211
now I want to allow that OR:
gamedate=20131211,20131212
That requires modifying the code above to try to split the comma delimited string and parse each value into a Date and change the interface to findByDate to accept a Seq[DateTime] vs just DateTime. I tried running something like this, but apparently it's not the way to go about it:
val res = gdates match {
case Some(s) => {
val dates:Option[Seq[DateTime]] = gdates map { _.split(",").distinct.map(MyDateTime.parseDate _ )}
val datesOrDefault:Seq[DateTime] = dates map { _.getOrElse((new DateTime).withTime(0, 0, 0, 0))}
NBAScoreboard.findByDates(datesOrDefault)
}
case None => NBAScoreboard.getToday
}
What's the best way to convert my first set of code to handle this use case? I'm probably fairly close in the second code example I provided, but I'm just not hitting it right.
You mixed up the containers. The map you call on dates unpackes the Option so the getOrElse is applied to a list.
val res = gdates match {
case Some(s) =>
val dates = gdates.map(_.split(",").distinct.map(MyDateTime.parseDate _ ))
val datesOrDefault = dates.getOrElse(Array((new DateTime).withTime(0, 0, 0, 0)))
NBAScoreboard.findByDates(datesOrDefault)
case _ =>
NBAScoreboard.getToday
}
This should work.