I'm getting error summing a List using the .fold() method:
List<int> listInt = [1, 2, 3, 4, 5, 6];
int sumList = listInt.fold(0, (p, c) => p + c);
// First Print
print(sumList);
// Second Pring
print(listInt.fold(0, (p, c) => p + c));
Printing sumList is perfectly fine, but when I print the same operation i get a compilation error:
The operator '+' can't be unconditionally invoked because the receiver can be 'null'.
Any ideas why?
A case where the Dart type system is not smart enough to guess the correct type. What happens in your second line is that fold thinks you want a Object? returned so p becomes Object?.
In the first example, the Dart type system guesses the type based on the expected returned type which is int in your case. But because print expects Object?, you are really not getting the type you expect.
The reason is that the Dart type system does not really understand the concept of defining the returned type of a method given as second argument based on the type of the first argument. So fold is often problematic here if we don't have an typed output.
We can force it to understand what we want by changing your second line to:
print(listInt.fold<int>(0, (p, c) => p + c));
And it should work as you want.
Related
Here is a function:
let newPositions : PositionData list =
positions
|> List.filter (fun x ->
let key = (x.Instrument, x.Side)
match brain.Positions.TryGetValue key with
| false, _ ->
// if we don't know the position, it's new
true
| true, p when x.UpdateTime > p.UpdateTime ->
// it's newer than the version we have, it's new
true
| _ ->
false
)
it compiles at expected.
let's focus on two lines:
let key = (x.Instrument, x.Side)
match brain.Positions.TryGetValue key with
brain.Positions is a Map<Instrument * Side, PositionData> type
if I modify the second line to:
match brain.Positions.TryGetValue (x.Instrument, x.Side) with
then the code will not compile, with error:
[FS0001] This expression was expected to have type
'Instrument * Side'
but here has type
'Instrument'
but:
match brain.Positions.TryGetValue ((x.Instrument, x.Side)) with
will compile...
why is that?
This is due to method call syntax.
TryGetValue is not a function, but a method. A very different thing, and a much worse thing in general. And subject to some special syntactic rules.
This method, you see, actually has two parameters, not one. The first parameter is a key, as you expect. And the second parameter is what's known in C# as out parameter - i.e. kind of a second return value. The way it was originally meant to be called in C# is something like this:
Dictionary<int, string> map = ...
string val;
if (map.TryGetValue(42, out val)) { ... }
The "regular" return value of TryGetValue is a boolean signifying whether the key was even found. And the "extra" return value, denoted here out val, is the value corresponding to the key.
This is, of course, extremely awkward, but it did not stop the early .NET libraries from using this pattern very widely. So F# has special syntactic sugar for this pattern: if you pass just one parameter, then the result becomes a tuple consisting of the "actual" return value and the out parameter. Which is what you're matching against in your code.
But of course, F# cannot prevent you from using the method exactly as designed, so you're free to pass two parameters as well - the first one being the key and the second one being a byref cell (which is F# equivalent of out).
And here is where this clashes with the method call syntax. You see, in .NET all methods are uncurried, meaning their arguments are all effectively tupled. So when you call a method, you're passing a tuple.
And this is what happens in this case: as soon as you add parentheses, the compiler interprets that as an attempt to call a .NET method with tupled arguments:
brain.Positions.TryGetValue (x.Instrument, x.Side)
^ ^
first arg |
second arg
And in this case it expects the first argument to be of type Instrument * Side, but you're clearly passing just an Instrument. Which is exactly what the error message tells you: "expected to have type 'Instrument * Side'
but here has type 'Instrument'".
But when you add a second pair of parens, the meaning changes: now the outer parens are interpreted as "method call syntax", and the inner parens are interpreted as "denoting a tuple". So now the compiler interprets the whole thing as just a single argument, and all works as before.
Incidentally, the following will also work:
brain.Positions.TryGetValue <| (x.Instrument, x.Side)
This works because now it's no longer a "method call" syntax, because the parens do not immediately follow the method name.
But a much better solution is, as always, do not use methods, use functions instead!
In this particular example, instead of .TryGetValue, use Map.tryFind. It's the same thing, but in proper function form. Not a method. A function.
brain.Positions |> Map.tryFind (x.Instrument, x.Side)
Q: But why does this confusing method even exist?
Compatibility. As always with awkward and nonsensical things, the answer is: compatibility.
The standard .NET library has this interface System.Collections.Generic.IDictionary, and it's on that interface that the TryGetValue method is defined. And every dictionary-like type, including Map, is generally expected to implement that interface. So here you go.
In future, please consider the Stack Overflow guidelines provided under How to create a Minimal, Reproducible Example. Well, minimal and reproducible the code in your question is, but it shall also be complete...
…Complete – Provide all parts someone else needs to reproduce your
problem in the question itself
That being said, when given the following definitions, your code will compile:
type Instrument() = class end
type Side() = class end
type PositionData = { Instrument : Instrument; Side : Side; }
with member __.UpdateTime = 0
module brain =
let Positions = dict[(Instrument(), Side()), {Instrument = Instrument(); Side = Side()}]
let positions = []
Now, why is that? Technically, it is because of the mechanism described in the F# 4.1 Language Specification under §14.4 Method Application Resolution, 4. c., 2nd bullet point:
If all formal parameters in the suffix are “out” arguments with byref
type, remove the suffix from UnnamedFormalArgs and call it
ImplicitlyReturnedFormalArgs.
This is supported by the signature of the method call in question:
System.Collections.Generic.IDictionary.TryGetValue(key: Instrument * Side, value: byref<PositionData>)
Here, if the second argument is not provided, the compiler does the implicit conversion to a tuple return type as described in §14.4 5. g.
You are obviously familiar with this behaviour, but maybe not with the fact that if you specify two arguments, the compiler will see the second of them as the explicit byref "out" argument, and complains accordingly with its next error message:
Error 2 This expression was expected to have type
PositionData ref
but here has type
Side
This misunderstanding changes the return type of the method call from bool * PositionData to bool, which consequently elicits a third error:
Error 3 This expression was expected to have type
bool
but here has type
'a * 'b
In short, your self-discovered workaround with double parentheses is indeed the way to tell the compiler: No, I am giving you only one argument (a tuple), so that you can implicitly convert the byref "out" argument to a tuple return type.
The following code used to work in Dart 2.6 (very simplified example!):
T plus<T extends num>(T a, T b) => a + b;
Now it fails with: A value of type 'num' can't be returned from method 'plus' because it has a return type of 'T'.
Is there a way to abstract over double/int like intended in the example?
I'm assuming you are passing the --no-implicit-casts flag to the analyzer in order to get this error. The code is correct in the current Dart language, but it contains an implicit cast, so if you choose to disable those, the code will not be accepted.
The reason the code does not work is that the static type of a + b is num (both have type T which is only known to extend num, so they are treated as num, and num.operator+ returns num), and the return type is T which may extend num.
So, the code does an implicit cast from num to T if you allow it.
To make the code compile even without implicit casts, you have to turn it into an explicit cast:
T plus<T extends num>(T a, T b) => (a + b) as T;
Why Dart allow me to store Iterable<T> in List<T> variable?
List<int> list = [1, 2, 3].map((i) => i);
It's caused a lot of problems when I use map function because it returns me Iterable<T> then I store to list variable.
When I try to get an element from list using list[0] it will cause an error.
Dart currently allows implicit downcasts.
When you try to store a value with static type S in a variable of a type T, then:
* If T is a supertype of S, then it just works.
* If S is a subtype of T, then the compiler inserts an implicit downcast to the subtype
* Otherwise it's a compile-time error.
This means that:
List<int> iterable = [1, 2, 3].map((e) => e);
is compiled as
List<int> iterable = [1, 2, 3].map((e) => e) as List<int>;
That will fail at runtime when it tries to do that cast. And it does fail.
It should not fail when you try to read an element, it should fail immediately when you try to assign the iterable to the list variable. If it doesn't, it's probably because you are compiling to JavaScript. The JavaScript compiler omits a number of run-time type checks under the assumption that they'll probably succeed (that's an unsafe optimization, but nevertheless an optimization with a significant impact). So, you are doing an unsafe downcast, the language inserts a check to make sure it's safe, then the compiler omits that check again, and you get the bad behavior later than intended.
Exactly the iterable/list subtyping has caused a lot of issues because it's so easy to accidentally create an iterable when you meant it to be a list.
When Dart introduces non-nullable types, it would get even worse, so at that point, it will remove the implicit downcast feature, and you will get an error when trying to assign an iterable to a list variable.
Call the .toList() method on the Iterable.
List<int> list = [1, 2, 3].map((i) => i).toList();
Your code throws a runtime error, even before using the [] operator, because the .map function returns an Iterable<T> (that doesn't have the [] operator) which cannot be cast to a List<T>. You either want to use .toList to convert your Iterable<T> to a List<T> or .elementAt(index) can be used instead of [].
For example:
var list = [1, 2, 3].map((e) => e).toList(); // Using .toMap
list[1]; // Get the second value.
var iterable = [1, 2, 3].map((e) => e); //Using elementAt
iterable.elementAt(1); // Get the second value.
I was given a question which was:
given a number N in the first argument selects only numbers greater than N in the list, so that
greater(2,[2,13,1,4,13]) = [13,4,13]
This was the solution provided:
member(_,[]) -> false;
member(H,[H|_]) -> true;
member(N,[_,T]) -> member(N,T).
I don't understand what "_" means. I understand it has something to do with pattern matching but I don't understand it completely. Could someone please explain this to me
This was the solution provided:
I think you are confused: the name of the solution function isn't even the same as the name of the function in the question. The member/2 function returns true when the first argument is an element of the list provided as the second argument, and it returns false otherwise.
I don't understand what "_" means. I understand it has something to do with pattern matching but I don't understand it completely. Could someone please explain this to me
_ is a variable name, and like any variable it will match anything. Here are some examples of pattern matching:
35> f(). %"Forget" or erase all variable bindings
ok
45> {X, Y} = {10, 20}.
{10,20}
46> X.
10
47> Y.
20
48> {X, Y} = {30, 20}.
** exception error: no match of right hand side value {30,
20}
Now why didn't line 48 match? X was already bound to 10 and Y to 20, so erlang replaces those variables with their values, which gives you:
48> {10, 20} = {30, 20}.
...and those tuples don't match.
Now lets try it with a variable named _:
49> f().
ok
50> {_, Y} = {10, 20}.
{10,20}
51> Y.
20
52> {_, Y} = {30, 20}.
{30,20}
53>
As you can see, the variable _ sort of works like the variable X, but notice that there is no error on line 52, like there was on line 48. That's because the _ variable works a little differently than X:
53> _.
* 1: variable '_' is unbound
In other words, _ is a variable name, so it will initially match anything, but unlike X, the variable _ is never bound/assigned a value, so you can use it over and over again without error to match anything.
The _ variable is also known as a don't care variable because you don't care what that variable matches because it's not important to your code, and you don't need to use its value.
Let's apply those lessons to your solution. This line:
member(N,[_,T]) -> member(N,T).
recursively calls the member function, namely member(N, T). And, the following function clause:
member(_,[]) -> false;
will match the function call member(N, T) whenever T is an empty list--no matter what the value of N is. In other words, once the given number N has not matched any element in the list, i.e. when the list is empty so there are no more elements to check, then the function clause:
member(_,[]) -> false;
will match and return false.
You could rewrite that function clause like this:
member(N, []) -> false;
but erlang will warn you that N is an unused variable in the body of the function, which is a way of saying: "Are you sure you didn't make a mistake in your function definition? You defined a variable named N, but then you didn't use it in the body of the function!" The way you tell erlang that the function definition is indeed correct is to change the variable name N to _ (or _N).
It means a variable you don't care to name. If you are never going to use a variable inside the function you can just use underscore.
% if the list is empty, it has no members
member(_, []) -> false.
% if the element I am searching for is the head of the list, it is a member
member(H,[H|_]) -> true.
% if the elem I am searching for is not the head of the list, and the list
% is not empty, lets recursively go look at the tail of the list to see if
% it is present there
member(H,[_|T]) -> member(H,T).
the above is pseudo code for what is happening. You can also have multiple '_' unnamed variables.
According to Documentation:
The anonymous variable is denoted by underscore (_) and can be used when a variable is required but its value can be ignored.
Example:
[H, _] = [1,2] % H will be 1
Also documentation says that:
Variables starting with underscore (_), for example, _Height, are normal variables, not anonymous. They are however ignored by the compiler in the sense that they do not generate any warnings for unused variables.
Sorry if this is repetitive...
What does (_,[]) mean?
That means (1) two parameters, (2) the first one matches anything and everything, yet I don't care about it (you're telling Erlang to just forget about its value via the underscore) and (3) the second parameter is an empty list.
Given that Erlang binds or matches values with variables (depending on the particular case), here you're basically looking to a match (like a conditional statement) of the second parameter with an empty list. If that match happens, the statement returns false. Otherwise, it tries to match the two parameters of the function call with one of the other two statements below it.
I have a rel[loc, str, int, int] which I aliased as ECCModel
Iterating over it in a function results in an error "Type of pattern could not be computed" when elements of the pattern are called location. When named anything other than location, the errors disappear. Is "location" a reserved word in Rascal? Regardless of the errors, it will compile and run just fine.
The error can be produced with the following method
alias ECCModel = rel[loc, str, int, int]
map[str,int] Foo(ECCModel bar)
{
return (y : z | <location, y, z, _> <- bar);
}
Is this expected behavior?
This is not expected behavior and location is not a reserved word, but loc is.
I think this is a glitch of the current compiler.
For your clarification: we currently have three implementations of Rascal:
The Rascal interpreter.
The current (also already sometimes called "old") compiler.
The new compiler we are working on that is not yet released.
Your example runs fine with the interpreter and new compiler. So the problem you are reporting will disappear over time.