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.
Related
It seems like there are two ways to return errors in an async workflow: raise and Result.
let willFailRaise = async {
return raise <| new Exception("oh no!")
}
let willFailResult = async {
return Result.Error "oh no!"
}
For the caller, the handling is a bit different:
async {
try
let! x = willFailRaise
// ...
with error ->
System.Console.WriteLine(error)
}
async {
let! maybeX = willFailResult
match maybeX with
| Result.Ok x ->
// ...
| Result.Error error ->
System.Console.WriteLine(error)
}
My questions are:
What are the advantages / disadvantages of each approach?
Which approach is more idiomatic F#?
It depends on what kind of error we are talking about. Basically there are three kinds:
Domain errors (e.g. user provided invalid data, user with this email is already registered, etc.)
Infrastructure errors (e.g you can't connect to another microservice or DB)
Panics (e.g. NullReferenceExceptionor StackOverflowException etc.), which are caused by programmers' mistakes.
While both approaches can get the job done, usually your concern should be to make your code as self-documented and easy-to-read as possible. Which means the following:
Domain errors: definitely go for Result. Those "errors" are expected, they are part of your workflow. Using Result reflects your business rules in function's signature, which is very useful.
Infrastructure failures: it depends. If you have microservices, then probably those failures are expected and maybe it would be more convenient to use Result. If not -- go for exceptions.
Panics: definitely Exception. First of all, you can't cover everything with Result, you gonna need global exception filter either way. Second thing -- if you try to cover all possible panics - code becomes a nasty disaster extremely fast, that will kill the whole point of using Result for domain errors.
So really this has nothing to do with Async or C# interop, it's about code readability and maintainability.
As for C# iterop -- don't worry, Result has all the methods to help, like IsError and so on. But you can always add an extension method:
[<AutoOpen>]
module Utils =
type Result<'Ok, 'Error> with
member this.Value =
match this with
| Ok v -> v
| Error e -> Exception(e.ToString()) |> raise
This is one of the many aspects of F# programming that suffers from the mind-split at the core of the language and its community.
On one hand you have "F# the .NET Framework language" where exceptions are the mechanism for handling errors, on the other - "F# the functional programming language" that borrows its idioms from the Haskell side of the world. This is where Result (also known as Either) comes from.
The answer to the question "which one is idiomatic" will change depending who you ask and what they have seen, but my experience has taught me that when in doubt, you're better off using exceptions. Result type has its uses in moderation, but result-heavy programming style easily gets out of hand, and once that happens it's not a pretty sight.
Raise
Advantages
Better .NET interop as throwing exceptions is fairly common in .NET
Can create custom Exceptions
Easier to get the stack trace as it's right there
You probably have to deal with exceptions from library code anyways in most standard async operations such as reading from a webpage
Works with older versions of F#
Disadvantages:
If you aren't aware of it potentially throwing an exception, you might not know to catch the exception. This could result in runtime explosions
Result
Advantages
Any caller of the async function will have to deal with the error, so runtime explosions should be avoided
Can use railway oriented programming style, which can make your code quite clean
Disadvantages
Only available in F# 4.1 or later
Difficult for non-F# languages to use it
The API for Result is not comprehensive.
There are only the functions bind, map, and mapError
Some functions that would be nice to have:
bimap : ('TSuccess -> 'a) -> ('TError -> 'e) -> Result<'TSuccess,'TError> -> Result<'a, 'e>
fold : ('TSuccess -> 'T) -> ('TError -> 'T) -> Result<'TSuccess, 'TError> -> 'T
isOk
Please unwrap these type signatures to help me understand why this doesn't work.
Then, if you have a solution, that would be great too.
I have this code and the agent.Post command has the signature Observer.Create<'T>(onNext: Action<'T>) : IObserver<'T>
let reservatinoRequestObserver = Observer.Create agent.Post
interface IHttpControllerActivator with
To my knowledge, this means that Observer.Create should take an Action with a single generic parameter and then return an IObserver.
Now the definition of Post is member MailboxProcessor.Post : message:'Msg ->unit
So... Post is a method, no? It is a method that takes a single parameter no? And it returns void no? So shouldn't it be a candidate for Observer.Create? Isn't that the exact specification of Action<'T>?
Well, somethings up, I get This function takes too many arguments, or is used in a context where a function is not expected:
Help me out... I freely admit I suck at F#
First, agent.Post returns unit, which is a different thing from void. F# will usually convert back and forth between void and unit for you, but they are not the same thing.
Second, F# functions do not implicitly convert to .NET delegates.
But there are some ways to do it:
You can explicitly create the delegate using its constructor:
let o = Observer.Create (new Action<_>( agent.Post ))
Lambdas are nicely wrapped too
let o = Observer.Create (fun msg -> agent.Post msg)
Use F# Rx-wrappers
Also there are a couple of F# wrappers/interop for Rx on nuget - just have a look, I think any will do
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 piece of erlang code which should read some values from a db and should support a couple of dbs. I wanted my code to be somehow not dependent from the db, so I implemented two different gen_servers that register both with the same atom (db_handler). I decide which version should be started reading the .app file.
The two gen_servers expose a common handle_call, so I can use in other parts of my application something like:
gen_server:call(db_handler, {do_something, "value1", "value2"})
This works, but still it is strongly coupled to the fact that each and any future implementation for a new db should be a gen_server.
I was thinking of using the ! operator and handle the command in the handle_info, but still I think that a better solution is possible (maybe passing through another module?).
Can somebody give me some insight on the better way to handle something like this in erlang?
For each db server add a common interface to abstract the call:
-module(db_server1).
...
do_something([Value1,Value2]) -> gen_server:call(db_handler, {do_something, "value1", "value2"}).
...
another one not using gen server
-module(db_server2).
...
do_something([Value1,Value2]) -> something_else({do_something, "value1", "value2"}).
...
create a new process (a gen_server :o) which receive as init parameter the param which is used to select the db server and store it in its state (for example db_server2),
for each do_something function, implement a function like:
do_something(Value1,Value2) -> gen_server:call(db_handler, {do_something, ["value1", "value2"]}).
...
handle_call({Func, Args}, _From, DB_server) ->
R = DB_server:F(Args),
{reply, R, DB_server}.
same thing for non blocking interfaces, using cast or equivalent
Each database driver could be a library module that exposes functions for your gen_server.
handle_call({do_something, Driver, Value1, Value2}, _From, State) ->
Reply = Driver:do_something(Value1, Value2),
{reply, Reply, State}.
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).