[erlang-questions] guards

45 views
Skip to first unread message

Dave Pawson

unread,
Jul 24, 2009, 10:50:13 PM7/24/09
to Erlang Questions
filterHelper(Lst,Int,Result) when ((length(Lst) == 1) and
(lists:nth(1,Lst) =< Int)) ->
[lists:nth(1,Lst) | Result];

and I'm told

./math4.erl:132: illegal guard expression


I believe I can't use 'user defined' references in a guard statement,
but I'm unsure if lists: module is such a statement?

Suggestions please

TIA

--
Dave Pawson
XSLT XSL-FO FAQ.
Docbook FAQ.
http://www.dpawson.co.uk

________________________________________________________________
erlang-questions mailing list. See http://www.erlang.org/faq.html
erlang-questions (at) erlang.org

James Hague

unread,
Jul 24, 2009, 11:13:24 PM7/24/09
to Erlang Questions
> I believe I can't use 'user defined' references in a guard statement,
> but I'm unsure if  lists: module is such a statement?

lists:nth is not allowed in guards. It's a pretty short list, the
functions that are allowed.

Michael Truog

unread,
Jul 24, 2009, 11:28:21 PM7/24/09
to Dave Pawson, Erlang Questions
- Can't use parentheses in guards
- All the guards are in the erlang module and are explicitly documented
as allowed in guard expressions
(usually is_something/1, erlang:length/1 works but supposedly is O(n),
not O(1) like the others)
- use "," for and, otherwise ";" for or... they evaluate in a sequential way
- Guards help to catch errors early and give hints for optimizations, if
they can occur
- Specifying the type in the function argument is always faster than
adding a guard function for the type
(as seen in the "The is_record() guard" thread)

Dave Pawson wrote:
> filterHelper(Lst,Int,Result) when ((length(Lst) == 1) and
> (lists:nth(1,Lst) =< Int)) ->
> [lists:nth(1,Lst) | Result];
>
> and I'm told
>
> ./math4.erl:132: illegal guard expression
>
>
> I believe I can't use 'user defined' references in a guard statement,
> but I'm unsure if lists: module is such a statement?
>
> Suggestions please
>
> TIA
>
>

Dave Pawson

unread,
Jul 24, 2009, 11:27:30 PM7/24/09
to James Hague, Erlang Questions
Tks James

2009/7/25 James Hague <james...@gmail.com>:


>> I believe I can't use 'user defined' references in a guard statement,
>> but I'm unsure if  lists: module is such a statement?
>
> lists:nth is not allowed in guards.  It's a pretty short list, the
> functions that are allowed.

http://www.erlang.org/doc/reference_manual/expressions.html#6.24

In case anyone else is curious what the list is!

regards


--
Dave Pawson
XSLT XSL-FO FAQ.
Docbook FAQ.
http://www.dpawson.co.uk

________________________________________________________________

Dave Pawson

unread,
Jul 24, 2009, 11:31:33 PM7/24/09
to Michael Truog, Erlang Questions
2009/7/25 Michael Truog <mjt...@gmail.com>:

> - Can't use parentheses in guards
> - All the guards are in the erlang module and are explicitly documented
> as allowed in guard expressions
>  (usually is_something/1, erlang:length/1 works but supposedly is O(n),
> not O(1) like the others)
> - use "," for and, otherwise ";" for or... they evaluate in a sequential way

Thanks. Not clear in the book I'm using (uses guard(X,Y) when ....
and ... or => etc.


> - Specifying the type in the function argument is always faster than
> adding a guard function for the type
>   (as seen in the "The is_record() guard" thread)

I'll go hunting!


regards

--
Dave Pawson
XSLT XSL-FO FAQ.
Docbook FAQ.
http://www.dpawson.co.uk

________________________________________________________________

Dave Pawson

unread,
Jul 25, 2009, 4:46:55 AM7/25/09
to Hynek Vychodil, Erlang Questions
2009/7/25 Hynek Vychodil <vychodi...@gmail.com>:

>
>
> On Sat, Jul 25, 2009 at 4:50 AM, Dave Pawson <dave....@gmail.com> wrote:
>>
>> filterHelper(Lst,Int,Result) when ((length(Lst) == 1) and
>> (lists:nth(1,Lst) =< Int)) ->
>>    [lists:nth(1,Lst) | Result];
>
> It is little bit overcomplicated version of
>
> filterHelper([X], Int, Result) when X =< Int -> [X|Result];

Mmm. Thanks... I think :-)
(I'm trying to learn!)

Does that check for a list length of 1?
As well as the value being <= (who the heck chose =<
that is a real kludge!!!) Int?

>
> and also lists:nth(1,L) is equivalent of hd(L) which can be used in guards
> but in most of time use list decomposition in pattern match is more
> effective way to do it.

Ah! Didn't know about hd(L).
Is there a quick reference chart for Erlang Bofs, perhaps the common
module functions?
Seems its something to fight going into any language!

Thanks Kynek.


regards

Johnny Billquist

unread,
Jul 25, 2009, 5:03:41 AM7/25/09
to Dave Pawson, Hynek Vychodil, Erlang Questions
Dave Pawson wrote:
> 2009/7/25 Hynek Vychodil <vychodi...@gmail.com>:
>>
>> On Sat, Jul 25, 2009 at 4:50 AM, Dave Pawson <dave....@gmail.com> wrote:
>>> filterHelper(Lst,Int,Result) when ((length(Lst) == 1) and
>>> (lists:nth(1,Lst) =< Int)) ->
>>> [lists:nth(1,Lst) | Result];
>> It is little bit overcomplicated version of
>>
>> filterHelper([X], Int, Result) when X =< Int -> [X|Result];
>
> Mmm. Thanks... I think :-)
> (I'm trying to learn!)
>
> Does that check for a list length of 1?

A pattern of [X] can only match a list with one element.
If the list have two elements, you'd have to write [X,Y] to match, and
so on...
If you want to match a list of unknown length, where you want to look at
the first element, you should write [X|Y]. Y will then be the list with
all the remaining elements after the first, which is bound to X.
Check the first two elements by [X,Y|Z], and so on...

And of course, to match a list with no elements, you write []. :-)

Johnny

--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: b...@softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol

Dave Pawson

unread,
Jul 25, 2009, 5:11:54 AM7/25/09
to Johnny Billquist, Hynek Vychodil, Erlang Questions
2009/7/25 Johnny Billquist <b...@softjar.se>:

>>> It is little bit overcomplicated version of
>>>
>>> filterHelper([X], Int, Result) when X =< Int -> [X|Result];
>>
>> Mmm. Thanks... I think :-)
>> (I'm trying to learn!)
>>
>> Does that check for a list length of 1?
>
> A pattern of [X] can only match a list with one element.

Couldn't X be a variable which might be a tuple or ... almost anything?
Or is this pattern matching logic, that implies it is as you say?


> If the list have two elements, you'd have to write [X,Y] to match, and so
> on...

Yes. Two element list would require the comma


> If you want to match a list of unknown length, where you want to look at the
> first element, you should write [X|Y].

I'm getting used to that pattern, very useful!

Thanks.

--
Dave Pawson
XSLT XSL-FO FAQ.
Docbook FAQ.
http://www.dpawson.co.uk

________________________________________________________________

Martin Engström

unread,
Jul 25, 2009, 5:23:20 AM7/25/09
to Dave Pawson, Erlang Questions
On Sat, Jul 25, 2009 at 11:11 AM, Dave Pawson <dave....@gmail.com> wrote:

> 2009/7/25 Johnny Billquist <b...@softjar.se>:
>
> >>> It is little bit overcomplicated version of
> >>>
> >>> filterHelper([X], Int, Result) when X =< Int -> [X|Result];
> >>
> >> Mmm. Thanks... I think :-)
> >> (I'm trying to learn!)
> >>
> >> Does that check for a list length of 1?
> >
> > A pattern of [X] can only match a list with one element.
>
> Couldn't X be a variable which might be a tuple or ... almost anything?
> Or is this pattern matching logic, that implies it is as you say?
>

Yes, X would match anything. But [X] matches only a list with exactly one
element. ;)
/Martin

Johnny Billquist

unread,
Jul 25, 2009, 5:51:48 AM7/25/09
to Dave Pawson, Hynek Vychodil, Erlang Questions
Dave Pawson wrote:
> 2009/7/25 Johnny Billquist <b...@softjar.se>:
>
>>>> It is little bit overcomplicated version of
>>>>
>>>> filterHelper([X], Int, Result) when X =< Int -> [X|Result];
>>> Mmm. Thanks... I think :-)
>>> (I'm trying to learn!)
>>>
>>> Does that check for a list length of 1?
>> A pattern of [X] can only match a list with one element.
>
> Couldn't X be a variable which might be a tuple or ... almost anything?
> Or is this pattern matching logic, that implies it is as you say?

I'm making the assumption that X is unbound at the time, otherwise we
have a different ballgame where much less will match (in fact, only a
list, of which the only element is identical to whatever X is bound to).

The *only* element in the list could, however, be a list, a tuple, or
just about anything. There is no limits to what it could be. The point
is, that that is the only element in the list. If you want to check
further into what type of element you have in the list, then you could
either expand the pattern more, or add guards. Guards are useful when
you want to check some general property of the element, but for explicit
details, pattern matching makes more sense.

Assume that the list should hold just one element, and that one element
should be a tuple with two elements. That would then match against the
pattern [{X,Y}]

If the first element of the tuple should be 'foo', then the pattern
could be [{foo,X}]

No need to use guards to check for that. However, if the list should
hold one element, and that should be a tuple, but you don't know what
kind of tuple, then you'd need a guard, as in:

foo([X]) when is_tuple(X) ->

because the pattern can't specify a tuple with a variable number of
elements.

Johnny

--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: b...@softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol

________________________________________________________________

Dave Pawson

unread,
Jul 25, 2009, 6:00:12 AM7/25/09
to Johnny Billquist, Erlang Questions
2009/7/25 Johnny Billquist <b...@softjar.se>:

>>> A pattern of [X] can only match a list with one element.
>>
>> Couldn't X be a variable which might be a tuple or ... almost anything?
>> Or is this pattern matching logic, that implies it is as you say?
>
> I'm making the assumption that X is unbound at the time, otherwise we have a
> different ballgame where much less will match (in fact, only a list, of
> which the only element is identical to whatever X is bound to).

Yes. Thanks. I hadn't gone that far. No matter what ?type? it is,
there is only one of them in the list!

>
> The *only* element in the list could, however, be a list, a tuple, or just
> about anything. There is no limits to what it could be. The point is, that
> that is the only element in the list.

Two stage logic. It's a list length one, then deal with the list item.
I'll get there eventually!


> No need to use guards to check for that. However, if the list should hold
> one element, and that should be a tuple, but you don't know what kind of
> tuple, then you'd need a guard, as in:
>
> foo([X]) when is_tuple(X) ->
>
> because the pattern can't specify a tuple with a variable number of
> elements.

Thanks.

--
Dave Pawson
XSLT XSL-FO FAQ.
Docbook FAQ.
http://www.dpawson.co.uk

________________________________________________________________

Witold Baryluk

unread,
Jul 25, 2009, 12:01:38 PM7/25/09
to Dave Pawson, Erlang Questions
Dnia 2009-07-25, sob o godzinie 03:50 +0100, Dave Pawson pisze:

> filterHelper(Lst,Int,Result) when ((length(Lst) == 1) and
> (lists:nth(1,Lst) =< Int)) ->
> [lists:nth(1,Lst) | Result];

filterHelper([Elem],Int,Result) when Elem =< Int ->
[Elem | Result];

simpler and a lot faster.

--
Witold Baryluk <bar...@smp.if.uj.edu.pl>

Witold Baryluk

unread,
Jul 25, 2009, 1:31:22 PM7/25/09
to erlang-questions
Dnia 2009-07-25, sob o godzinie 18:04 +0100, Dave Pawson pisze:
> Thanks Witold,
>
> 2009/7/25 Witold Baryluk <bar...@smp.if.uj.edu.pl>:

> > Dnia 2009-07-25, sob o godzinie 03:50 +0100, Dave Pawson pisze:
> >> filterHelper(Lst,Int,Result) when ((length(Lst) == 1) and
> >> (lists:nth(1,Lst) =< Int)) ->
> >> [lists:nth(1,Lst) | Result];
> >
> > filterHelper([Elem],Int,Result) when Elem =< Int ->
> > [Elem | Result];
> >
> > simpler and a lot faster.
>
>
> I'm looking for understanding today,
> not speed!
>
> Speed will come, but later!
> I did not understand the [A] idea, that it is a list of one element!

Pattern matching is powerful and i hope you would like it :)

so this "simpler" part.

for example if you would like to only match one element lists with,
value like second argument:

filetrHelper([Int], Int, result) ->
...

(eventually adding is_integer/1 test)


"a lot faster" for two reasons.

1. compiler knows easier what is here, and extracts first (and only one)
element of the list, and reuse it in the body of function clause.
additionally if you have more clauses, compiler can more easily
find common structure between them and do checks in best possible way.
For example if two of them check if it have length == 1, check will
be done only once, i hope, this is just a theory. In case of guards
compiler probably isn't so smart.

2. I assumed this filterHelper is used in some kind of loop,
so it is for example called N times. What if most times the first
argument of filterHelper is actually big list (with K elements on
avarage?). You will end traversing all this lists (there is no
precomputed length of list, but thanks to this lists are smaller), only
for testing it if it is of some small (1) size. This makes this code
really slow, like N*K operations not just N. If K is large (10 or 100),
this is can be problematic.

This is the reasons why in my mind I see red alert blinking, always when
I find code with length/1 calls in guards. I would be happy
if it would be removed from allowed functions list in guards :)

Eventually it would be nice to have guard of the form length(List, Min,
Max), which would answer, if list List is of size between Min and Max
(or infinity) inclusive. So being equivalence of length(List) >=
Min ,length(List) =< Max, but faster. Only problem I see is with the
"inproper" lists, like [1|2], length throws exceptions for them.
So it is somehow unfortunete that there is no flag if lists is proper
or not. Probably for the same reason that there is no length field.
(or mayby this is because VM is doing some dirty tricks, and lists isn't
really immutable).

Reply all
Reply to author
Forward
0 new messages