illegal use of variable in erlang map - erlang

How can we create a map inside a function, then pass it as an argument to another function in erlang?
I was trying it in the following code:
-module(maps_all).
-export([test_my_map/2]).
test_my_map(K, V) ->
io:fwrite('~w ~w ~n done.',[K, V]),
nested_func(#{K => V}).
nested_func(MyMap) ->
io:fwrite('In nested function as map ~n ~w',[MyMap]).
This throws the error:
31> c(maps_all).
maps_all.erl:6: illegal use of variable 'K' in map
error

Also, this was added in Erlang 18 RC

For now (Erlang R17) there is no way to use variable directly in map expression.
You can achieve this with maps: new and put:
nested_func(maps:put(K, V, maps:new()))

Related

What is the correct syntax to Verify a mock logger call in F#?

I'm unit testing an F# function that calls ILogger.LogInformation. I'm attempting to verify that the function made the call as expected. Here is the verify statement I have so far:
let mockLogger = Mock<ILogger<MyFunction>>()
// call function that uses ILogger.LogInformation.
mockLogger.Verify(fun x -> x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once)
When I try this I get the following error:
System.ArgumentException: Expression of type 'System.Void' cannot be used for constructor parameter of type 'Microsoft.FSharp.Core.Unit' (Parameter 'a...
System.ArgumentException
Expression of type 'System.Void' cannot be used for constructor parameter of type 'Microsoft.FSharp.Core.Unit' (Parameter 'arguments[0]')
at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
at System.Dynamic.Utils.ExpressionUtils.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments, String methodParamName)
at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable`1 arguments)
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 616
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 599
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToLambdaExpression[T](FSharpExpr`1 e) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 698
The exception is thrown when it calls the Verify method. How can I change this to get past this error?
I don't know much about Moq, but I think part of the problem here is that you need another pair of parentheses around your lambda to separate it from the Times.Once argument. Try something like this instead:
mockLogger.Verify(
(fun x -> x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>())),
Times.Once)
Without the extra parens, your lambda returns a tuple, so your code is currently calling this method:
Verify: expression: Expression<Action<'T>> -> unit
But I think you want to call this method instead:
Verify: expression: Expression<Action<'T>> * times: Times -> unit
Here's a simpler example that should make the difference clear:
Verify(fun x -> x, 1) // call Verify with a single argument (a lambda that returns a tuple)
Verify((fun x -> x), 1) // call Verify with two arguments (a lambda and the literal value 1)

How should i match the Elmish toNavigable argument types

I'm trying to learn the SAFE Stack at the moment, specifically attempting to handle URL navigation via Elmish; I've followed the example code on the Elmish site that defines a route mapping function and then passes that to the parsePath function.
However, Program.toNavigable expects a Parser<'a> type (a type alias for Location -> 'a) as its first argument, but the sample code (parsePath routes) first argument is a Location -> 'a option.
Obviously i can use function composition to get the correct typing, but it seems like I'm missing something here. Can anyone familiar with URL navigation in Elmish advise?
Well, a Parser<'a option> is a Parser<'a> (just with another 'a), so things should compose just fine.
Say, e.g., that the following type defines all navigation:
type Route = Blog of int | Search of string
Then the parties involved should have the following types:
init: Route option -> Model * Cmd<Msg>
parser: Parser<Route option>
urlUpdate: Route option -> Model -> Model * Cmd<Msg>
and you compose your program thusly:
Program.mkProgram init update view
|> Program.toNavigable parser urlUpdate
|> Program.withReactBatched "elmish-app"
|> Program.run

how to format a throw statement in erlang

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.

erlang: function called with real 'fun' should be transformed with parse_transform?

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).

F# how to AddHandler alike VB.NET

VB.NET code is :
AddHandler TheGrp.DataChanged, AddressOf theGrp_DataChange
So how can I do same with F# ?
theGrp.DataChanged.AddHandler(X.theGrp_DataChange)
Error 1 This function takes too many arguments, or is used in a context where a function is not expected
Try theGrp.DataChanged.AddHandler(fun o e -> X.theGrp_DataChange(o, e)). The signature for AddHandler indicates that it takes a delegate, so you can either explicitly create one (via something like DataChangedEventHandler(fun o e -> X.theGrp_DataChange(o, e))) or you can let the compiler implicitly add the delegate constructor when given a function definition, but you can't just use the method itself.
Alternatively, if you don't want to create a lambda expression explicitly, you can also write (In this case, the function signature matches the signature required by the delegate, so it should work):
theGrp.DataChanged.AddHandler(DataChangedEventHandler(x.theGrp_DataChanged))
Also, if you don't need the sender argument, you can declare the theGrp_DataChanged method to take only the event args argument and then write just:
theGrp.DataChanged.Add(x.theGrp_DataChanged)

Resources