Tommy
Tommy

Reputation: 13632

Erlang: do list comprehension filters short circuit

Lets say I have:

 [ X || X<- L, some_expensive_boolean(X), some_expensive_boolean2(X)]

If, for any X in L, some_expensive_boolean(X) is false, is some_expensive_boolean2(X) executed?

Upvotes: 0

Views: 148

Answers (4)

juan.facorro
juan.facorro

Reputation: 9920

TL;DR: No, some_expensive_boolean2/1 is not called.

There a couple of ways you can verify this.

1. Having functions print something as they are called.

-module(lc).

-export([lc/1]).

lc(L) ->
  [X || X <- L, f(X), g(X)].

f(X = 2) ->
  erlang:display({f, 2}),
  false;
f(X) ->
  erlang:display({f, X}),
  true.

g(X) ->
  erlang:display({g, X}),
  true.

Then on the Erlang shell:

1> lc:lc(lists:seq(1, 4)).
{f,1}
{g,1}
{f,2} %% g is not called here
{f,3}
{g,3}
{f,4}
{g,4}
[1,3,4]

2. Check the generated Core Erlang code.

Compiling the module with the +to_core option will produce a lc.core file with the Core Erlang code, which looks a little bit like Erlang but has its own syntax but very similar semantics.

erlc +to_core lc.erl

The code generated is quite verbose so I won't paste it here, but the gist is that there are two nested case expressions, one calling f/1 with the clause that matches on true containing the other case that calls g/1.

Upvotes: 5

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26121

The answer is no. It is short-circuited.

1> [ X || X <-[1,2], begin io:format("Test 1: ~p~n", [X]), X rem 2 =:= 0 end, io:format("Test 2: ~p~n", [X]) =:= ok ].
Test 1: 1
Test 1: 2
Test 2: 2
[2]

Upvotes: 4

Marc Lambrichs
Marc Lambrichs

Reputation: 2882

Let's create an example:

$ cat test.erl
-module(test).

-export([show/0]).

show() ->
   [ X || X <- [1,2,3,4,5], bigger(X), smaller(X)].

bigger(X) ->
   io:format("bigger ~p~n", [X]),
   X > 2.

smaller(X) ->
   io:format("smaller ~p~n", [X]),
   X < 4.

and test it:

14> c(test).
{ok,test}
15> test:show().
bigger 1
bigger 2
bigger 3
smaller 3
bigger 4
smaller 4
bigger 5
smaller 5
[3]

So the answer is: NO.

Upvotes: 1

Derek Brown
Derek Brown

Reputation: 511

Short-circuits based on the following:

-module(shortcircuit).

-export([test/0]).

test() ->
  L = [1, 2, 3],
  [ X || X <- L, some_expensive_boolean(X), some_expensive_boolean2(X)].

some_expensive_boolean(X) ->
  io:format("In some_expensive_boolean: ~p~n", [X]),
  false.

some_expensive_boolean2(X) ->
  io:format("In some_expensive_boolean2: ~p~n", [X]),
  true.

Execute:

1> shortcircuit:test().
In some_expensive_boolean: 1
In some_expensive_boolean: 2
In some_expensive_boolean: 3
[]
2> 

Upvotes: 3

Related Questions