List foreach syntax

I want to iterate over a list of address and need to require some property for each address. Can someone help me with the syntax?

For example, I have the following state element,
user_is_processing: map(address, bool)

And I want to check each of the user address against this map supplied in the form of a list to a function. I want to require that each user in the list is not already processing, i.e. user_is_processing[user] == false.

Here’s something I’ve written but it doesn’t work.

public stateful entrypoint example(users: list(address)) =
   require(List.foreach(users, (user) => state.user_is_processing[user] == false))

As from the documentation

  • foreach Evaluates f on each element of a list
  • all Checks if all elements of a list fulfill predicate p

also as your user_is_processing[user] is already boolean state.user_is_processing[user] == false is superfluous and can just be negated with !

Yes, you are on the right path, but as you found out not 100% correct. There are a couple of things that is wrong, mainly the types don’t match.

So, if you want to use require it is defined as:

function require(b : bool, err : string) =
    if(!b) abort(err)

i.e. it takes two arguments, the first should be a boolean and the second the abort message. To produce a boolean you can not use List.foreach since its type is List.foreach(l : list('a), f : 'a => unit) : unit - i.e. it returns a unit which is not a boolean. Instead I suggest we use List.all, it has the type List.all(p : 'a => bool, l : list('a)) : bool - it will return true if the function in the first argument evaluates to true when applied to each element of the list in the second argument. So something like:
require(List.all((u) => !state.user_is_processing[u], users), "ERROR")

But, we are not there yet, this would be correct if every address is in user_is_processing but this isn’t Solidity and only the addresses you put in there will be available so I’d use state.user_is_processing[u = false] to default non-existing addresses to be non-processing.

So using:
require(List.all((u) => !state.user_is_processing[u = false], users), "ERROR")
should do the trick I think.

1 Like

Right, I missed the all function. I’ll use that itself. That should do the job. Thanks!

require( List.all( !state.user_is_processing, users ) )

So something like this should work, right?

Thanks for such a detailed response.

I tried something like that, using a helper function to do the job.

function helper(user: address) = 
    if(Map.member(user,  state.user_is_processing) && state.user_is_processing[user])

and then just

List.foreach(users, helper)

But as you and @philipp.chain pointed out, I think all would be the way to go about it.

Would this work?
require( List.all( !state.user_is_processing, users ) )

No, that will not compile since require takes two arguments and !state.user_is_processing is not a function :wink:

I’ll stick with my initial suggestion.