I'm trying to write a method that does something like this
Mono<A> ma = networkCall(); //this might fail
Mono<Void> mv = ma.map( a -> ....) #some logic to perform with `A`
return mv;
The trick is, ma might very well fail and then I would want to just log the situation and return a Mono<Void> that completes with no error.
Looking at the Mono api I just found onErrorResume or onErrorReturn but both would take a function that returns an A (which I can't fabricate), while I would like to return a Void.
I would imagine the solution is quite simple, but couldn't quite find the right operations for this.
So, what operations should I apply to ma to transform it into a Mono<Void> in case of error?
I just found onErrorResume or onErrorReturn but both would take a function that returns an A
onErrorReturn() indeed requires you to return an A, but onErrorResume() just requires you to return a Mono<A>, which can be empty.
So you can use:
doOnNext() to perform your logic with A if the call is successful;
doOnError() to log your error if the call is not successful;
onErrorResume() to return an empty result
then() to convert the result into a Mono<Void>.
Something like:
networkCall()
.doOnNext(a -> doSomethingWith(a))
.doOnError(e -> e.printStackTrace())
.onErrorResume(e -> Mono.empty())
.then();
I am new to Erlang syntax and struggling with this
I can do this and compile
throw(Reason)
which is of type throw/1
I want to be able to do this:
%% I have seen this code in sample examples.
?THROW("Couldn't start process: ~p. ~n", [Reason])
I do not think there there is throw/2.
Then how can I define a macro like above?
?THROW is a macro. It should be define somewhere as:
-define(THROW(Format,Params),throw(io_lib:format(Format,Params))).
In this definition, the call to io_lib:format(Format,Params) returns a single string that is used as Reason by the function throw.
I have a very simple Erlang program:
-module(test).
-export([start/0]).
Code = "Z00887".
start() -> io:fwrite(Code).
And I have follows two errors:
c:/erl6.1/dev/test.erl:4: syntax error before: Code
c:/erl6.1/dev/test.erl:5: variable 'Code' is unbound
Could you please help me correctly using variables in my code.
You are defining a variable that is global to the module, which is not allowed. Remember, "variables" in Erlang are really "symbols", so there is no concept of a "global" constant across all functions or processes. The closest thing to this in Erlang would be a macro defined in the module, but if a value is only needed in one place and you want to name it then this must be done within the function definition.
Also, do not use io:fwrite/1 or io:format/1. The problem is the possible inclusion of escape characters in the string you are passing. For example, this causes an error: Code = "Wee~!", io:format(Code). and it will not be caught by the compiler.
The most common thing to do is define a variable within the function:
-module(foo).
-export([start/0]).
start() ->
Code = "Z00887",
io:fwrite("~p~n", [Code]).
You could also just use the value directly:
-module(foo).
-export([start/0]).
start() ->
io:fwrite("Z00887~n").
Or you could define a macro across the whole module:
-module(foo).
-export([start/0]).
-define(CODE, "Z00887").
start() ->
io:fwrite("~p~n", [?CODE]).
Or you could even define a stub function that returns what you want:
-module(foo).
-export([start/0]).
start() ->
io:fwrite("~p~n", [code()]).
code() -> "Z00887".
This last version is actually not as weird as it may seem at first. Very often when developing some code early on you will know you need a value somewhere that you will need to derive in some way, but don't want to worry about the details of it just yet. A stub function is an excellent way to hide the details of how you will do that in the future without writing macro code, variable definitions, etc. that you will have to remember to go back and change later. For example, the last example above will almost certainly change to something like this in the future:
-module(foo).
-export([start/0]).
start() ->
io:fwrite("~p~n", [code()]).
code() ->
{ok, Code} = some_init_module:get_code(),
Code.
Keep this in mind. It makes Erlang almost as prototype-friendly as Guile or Scheme.
I'm trying to write a function that does type casting, which seems to be a frequently occurring activity in Rascal code. But I can't seem to get it right. The following and several variations on it fail.
public &T cast(type[&T] tp, value v) throws str {
if (tp tv := v)
return tv;
else
throw "cast failed";
}
Can someone help me out?
Some more info: I frequently use pattern matching against a pattern of the form "Type Var" (i.e. against a variable declaration) in order to tell Rascal that an expression has a certain type, e.g.
map[str,value] m := myexp
This is usually in cases where I know that myexp has type map[str,value], but omitting the matching would make Rascal's type checking mechanism complain.
In order to be a bit more defensive against mistakes, I usually wrap the matching construct in an if-then-else where an exception is raised if the match fails:
if (map[str,value] m := myexp) {
// use m
} else {
throw "cast failed";
}
I would like to shorten all such similar pieces of code using a single function that does the job generically, so that I can write instead
cast(#map[str,value], myexp)
PS. Also see How to cast a value type to Map in Rascal?
It seems that the best way to write this, if you truly need to do this, is the following:
public map[str,value] cast(map[str,value] v) = v;
public default map[str,value] cast(value v) { throw "cast failed!"; }
Then you could just say
m = cast(myexp);
and it would do what you want to do -- the actual pattern matching is moved into the function signature for cast, with a case specific to the type you are wanting to use and a case that handles everything that doesn't otherwise match.
However, I'm still not sure why you are using type value, either here (inside the map) or in the linked question. The "standard" Rascal way of handling cases where you could have one of multiple choices is to define these with a user-defined data type and constructors. You could then use pattern matching to match the constructors, or use the is and has keywords to interrogate a value to check to see if it was created using a specific constructor or if it has a specific field, respectively. The rule for fields is that all occurrences of a field in the constructor definitions for a given ADT have the same type. So, it may help to know more about your usage scenario to see if this definition of cast is the best option or if there is a better solution to your problem.
EDITED
If you are reading JSON, an alternate way to do it is to use the JSON grammar and AST that also live in that part of the library (I think the one you are using is more of a stream reader, like our current text readers and writers, but I would need to look at the code more to be sure). You can then do something like this (long output included to give an idea of the results):
rascal>import lang::json::\syntax::JSON;
ok
rascal>import lang::json::ast::JSON;
ok
rascal>import lang::json::ast::Implode;
ok
ascal>js = buildAST(parse(#JSONText, |project://rascal/src/org/rascalmpl/library/lang/json/examples/twitter01.json|));
Value: object((
"since_id":integer(0),
"refresh_url":string("?since_id=202744362520678400&q=amsterdam&lang=en"),
"page":integer(1),
"since_id_str":string("0"),
"completed_in":float(0.058),
"results_per_page":integer(25),
"next_page":string("?page=2&max_id=202744362520678400&q=amsterdam&lang=en&rpp=25"),
"max_id_str":string("202744362520678400"),
"query":string("amsterdam"),
"max_id":integer(202744362520678400),
"results":array([
object((
"from_user":string("adekamel"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/2206104506\\/339515338_normal.jpg"),
"in_reply_to_status_id_str":string("202730522013728768"),
"to_user_id":integer(215350297),
"from_user_id_str":string("366868475"),
"geo":null(),
"in_reply_to_status_id":integer(202730522013728768),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/2206104506\\/339515338_normal.jpg"),
"to_user_id_str":string("215350297"),
"from_user_name":string("nurul amalya \\u1d54\\u1d25\\u1d54"),
"created_at":string("Wed, 16 May 2012 12:56:37 +0000"),
"id_str":string("202744362520678400"),
"text":string("#Donnalita122 #NaishahS #fatihahmS #oishiihotchoc #yummy_DDG #zaimar93 #syedames I\'m here at Amsterdam :O"),
"to_user":string("Donnalita122"),
"metadata":object(("result_type":string("recent"))),
"iso_language_code":string("en"),
"from_user_id":integer(366868475),
"source":string("<a href="http:\\/\\/blackberry.com\\/twitter" rel="nofollow">Twitter for BlackBerry\\u00ae<\\/a>"),
"id":integer(202744362520678400),
"to_user_name":string("Rahmadini Hairuddin")
)),
object((
"from_user":string("kelashby"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/1861086809\\/me_beach_normal.JPG"),
"to_user_id":integer(0),
"from_user_id_str":string("291446599"),
"geo":null(),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/1861086809\\/me_beach_normal.JPG"),
"to_user_id_str":string("0"),
"from_user_name":string("Kelly Ashby"),
"created_at":string("Wed, 16 May 2012 12:56:25 +0000"),
"id_str":string("202744310872018945"),
"text":string("45 days til freedom! Cannot wait! After Paris: London, maybe Amsterdam, then southern France, then CANADA!!!!"),
"to_user":null(),
"metadata":object(("result_type":string("recent"))),
"iso_language_code":string("en"),
"from_user_id":integer(291446599),
"source":string("<a href="http:\\/\\/mobile.twitter.com" rel="nofollow">Mobile Web<\\/a>"),
"id":integer(202744310872018945),
"to_user_name":null()
)),
object((
"from_user":string("johantolsma"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/1961917557\\/image_normal.jpg"),
"to_user_id":integer(0),
"from_user_id_str":string("23632499"),
"geo":null(),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/1961917557\\/image_normal.jpg"),
"to_user_id_str":string("0"),
"from_user_name":string("Johan Tolsma"),
"created_at":string("Wed, 16 May 2012 12:56:16 +0000"),
"id_str":string("202744274050236416"),
"text":string("RT #agerolemou: Office space for freelancers in Amsterdam http:\\/\\/t.co\\/6VfHuLeK"),
"to_user":null(),
"metadata":object(("result_type":string("recent"))),
"iso_language_code":string("en"),
"from_user_id":integer(23632499),
"source":string("<a href="http:\\/\\/itunes.apple.com\\/us\\/app\\/twitter\\/id409789998?mt=12" rel="nofollow">Twitter for Mac<\\/a>"),
"id":integer(202744274050236416),
"to_user_name":null()
)),
object((
"from_user":string("hellosophieg"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/2213055219\\/image_normal.jpg"),
"to_user_id":integer(0),
"from_user_id_str":string("41153106"),
"geo":null(),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/2213055219\\/image_normal.jp...
rascal>js is object;
bool: true
rascal>js.members<0>;
set[str]: {"since_id","refresh_url","page","since_id_str","completed_in","results_per_page","next_page","max_id_str","query","max_id","results"}
rascal>js.members["results_per_page"];
Value: integer(25)
You can then use pattern matching, over the types defined in lang::json::ast::json, to extract the information you need.
The code has a bug. This is the fixed code:
public &T cast(type[&T] tp, value v) throws str {
if (&T tv := v)
return tv;
else
throw "cast failed";
}
Note that we do not wish to include this in the standard library. Rather lets collect cases where we need it and find out how to fix it in another way.
If you find you need this casting often, then you might be avoiding the better parts of Rascal, such as pattern based dispatch. See also the answer by Mark Hills.
I'm looking at the O'Reilly Erlang Programming book and there's an example that is run in the erlang shell that looks like this:
17> MS = ets:fun2ms(fun({Name,Country,Job}) when Job /= cook ->
[Country,Name] end).
[ ....an erlang match expression is returned.... ]
18> ets:select(countries, MS).
[[ireland,sean],[ireland,chris]]
However, when I do something similar in my code (not in the shell):
Fun = fun({Type,_,_,ObjectId,PlayerId}) when Type==player_atom, PlayerId==2 -> ObjectId end,
MatchFun = ets:fun2ms(Fun),
PlayerObjectId = ets:select(?roster_table, MatchFun),
I get FUBAR:
exit:{badarg,{ets,fun2ms,[function,called,with,real,'fun',should,be,transformed,with,parse_transform,'or',called,with,a,'fun',generated,in,the,shell]}}
(As an aside, I wonder why the error isn't 'function called with....' Probably so io:format("~p", TheErrorMessage) will line wrap?)
Anyway, I have abandoned select in favor of ets:foldl, since the latter works and - through exceptions in the fun - allows me to terminate the traversal when the first item is found. But, I'm still curious...
...wha? (I did some reading on parse_transform, and I'm new enough to erlang that I'm missing the connection.)
The badarg exception is symptom of a built-in function (or a pseudo function, as in this case) called with a wrong parameter. In this case, the ets:fun2ms/1 function.
Reading from the official documentation:
fun2ms(LiteralFun) -> MatchSpec
Pseudo function that by means of a parse_transform translates
LiteralFun typed as parameter in the function call to a match_spec.
With "literal" is meant that the fun needs to textually be written as
the parameter of the function, it cannot be held in a variable which
in turn is passed to the function).