_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
strangely, this also works;
case foo() of
[] -> X = bar();
X -> ok
end
as long as X is bound in each clause, you're golden.
this might qualify as a gotcha.
mats
>
> X = case foo() of
> [] -> bar();
> X1 -> X1
> end
strangely, this also works;
case foo() of
[] -> X = bar();
X -> ok
end
as long as X is bound in each clause, you're golden.
this might qualify as a gotcha.
mats
Just the variable scope. Once you have run:
1> case [] of [] -> X = aaa; X -> ok end.
aaa
The variable X is now bound:
2> X.
aaa
If you forget it first:
3> f(X).
ok
Your second example will work:
4> case bbb of [] -> X = aaa; X -> ok end.
ok
-Vance
From section '6.8 Case' of the Erlang Reference Manual (Version 5.6.5)
"If there is no matching pattern with a true guard sequence, a case_clause run-time error will occur."
bbb does not match anything in the second case above; you could substitute
aaa for X in the second case and it would result the same.
3> X.
aaa
~Michael
>
> On Sun, Nov 16, 2008 at 4:42 AM, mats cronqvist <[1]ma...@kreditor.se>
> wrote:
>
> strangely, this also works;
> case foo() of
> [] -> X = bar();
> X -> ok
> end
> as long as X is bound in each clause, you're golden.
> this might qualify as a gotcha.
> mats
>
> References
>
> 1. mailto:ma...@kreditor.se
> _______________________________________________
> erlang-questions mailing list
> erlang-q...@erlang.org
> http://www.erlang.org/mailman/listinfo/erlang-questions
--
Michael McDaniel
Portland, Oregon, USA
http://autosys.us
Well, andalso/orelse (as someone suggested) don't work since they
require that expr1 and expr2 evaluate to booleans and nothing else.
> I cant for the life of me figure out what the most concise way of
> stating that is in erlang.
>
> perhaps
> X = if (T1=foo()) =/= [] -> T1, false -> bar() end
>
> it would nice to be able to say something like
> X = foo() otherwise bar().
X = case foo() of
[] -> bar();
X1 -> X1
end
If you need to check for other values as well, replace '[] ->' with
'X when X =:= [] ; X =:= 0 ; ... ->'
But I've always felt that this feature of Python/Perl/... boils down
to sloppy programming style. It basically means that the caller hopes
that the "empty or failure" case is signalled by one of the values
reconized as pseudo-booleans by the language (the programmer might
not actually know the exact interface of the called function, but
guessed that this would work), and the resulting code says nothing to
the reader about the actual set of return values. Furthermore, the
code might do the wrong thing if the function tries to return e.g. '0'
or '{}' on success (as opposed to False or None or whatever it usually
uses for failure). It simply makes the code a lot less tight than it
ought to be. And then, you still can't use the same idiom on abstract
data types to treat e.g. an empty set as "false".
/Richard
1> case [] of [] -> X = aaa; X -> ok end.aaa2> case bbb of [] -> X = aaa; X -> ok end.** exception error: no case clause matching bbbam I missing something?
On Sun, Nov 16, 2008 at 4:42 AM, mats cronqvist <ma...@kreditor.se> wrote:strangely, this also works;
case foo() of
[] -> X = bar();
X -> ok
end
as long as X is bound in each clause, you're golden.
this might qualify as a gotcha.
mats
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
damien morton wrote:
Still, what strikes me about the erlang libraries is the tremendous variety of techniques used to signal the return of a value or not.
Sometimes nil/Value, sometimes false/Value, sometimes []/[Value], sometimes false/{value,Value}
I've tried to promote {value,X}/none as a standard maybe-type, but it's
hard to do much about all the existing code out there.[]/[X] is ok for "searches" as in mnesia, where in some cases you can
For a function that can return 0 or 1 answers, I personally like the []/[Value] approach.
get several elements as a result, but as a general mechanism it always
makes a reader think "so, can I ever get more than one value here?", so
it's not good for clarity.
damien morton wrote:
...
X = case foo() of
I cant for the life of me figure out what the most concise way of stating that is in erlang.
perhaps
X = if (T1=foo()) =/= [] -> T1, false -> bar() end
it would nice to be able to say something like
X = foo() otherwise bar().
[] -> bar();
X1 -> X1
end
If you need to check for other values as well, replace '[] ->' with
'X when X =:= [] ; X =:= 0 ; ... ->'
But I've always felt that this feature of Python/Perl/... boils down
to sloppy programming style. It basically means that the caller hopes
that the "empty or failure" case is signalled by one of the values
reconized as pseudo-booleans by the language (the programmer might
not actually know the exact interface of the called function, but
guessed that this would work), and the resulting code says nothing to
the reader about the actual set of return values. Furthermore, the
code might do the wrong thing if the function tries to return e.g. '0'
or '{}' on success (as opposed to False or None or whatever it usually
uses for failure). It simply makes the code a lot less tight than it
ought to be. And then, you still can't use the same idiom on abstract
data types to treat e.g. an empty set as "false".
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
> I keep wanting to have python-like boolean expression evaluation, in
> which a value of nil, 0, an empty list or an empty tuple are
> considered to be false.
You could do it via a macro that expanded
?PY_OR(e1, e2)
to
case py_val(e1)
of {X} -> X
; false -> e2
end
where
py_val(undef) -> false; % Closer match for Undef than nil is
py_val(0) -> false;
py_val(0.0) -> false;
py_val([]) -> false;
py_val({}) -> false;
py_val(false) -> false;
py_val(X) -> {X}.
However, this really is not very Erlang-like.
(For one thing, it's not very Dialyser-friendly.)
Lisp had a single value used to represent logical falsehood (NIL),
the empty list ('() => NIL), and a three-letter atom ('NIL => NIL).
Scheme found it very useful to separate them (#f, '(), and 'NIL
are all different in Scheme). Erlang is closer to Scheme here.
It may be that you are trying to write Python in Erlang,
which isn't the best way to use Erlang.
It may also be that you don't have (m)any cases where
ALL of the 'false' values listed above are actually possible,
just many cases where one of them is possible and you would
like to use the same operator for all of them. Well, 'case'
is definitely the construct you want.
Can you provide some examples?
> I think you're looking for the andalso and orelse operators. You say:
>
> X = foo() orelse bar(),
>
> and bar() only gets called if the value of foo() is false.
However there is a strong restriction in Erlang that does not
exist in Lisp, Scheme, Smalltalk, &c and does not exist in
Python.
False or 42 => 42 in Python
42 or False => 42 in Python
1 == 2 orelse 42 => ERROR! in Erlang
42 orelse 1 == 2 => ERROR! in Erlang
In Erlang, both operands of an andalso or orelse operator
must return 'true' or 'false'. I strongly suspect that the
OP wants a non-empty list or tuple to count as true, rather
than as an error.
1 == 2 orelse throw(no_bool_return).
> Your 'must' statement is not entirely accurate.
Was there any doubt about what I meant?
Let's try again:
both 'andalso' and 'orelse' in Erlang have the
following properties:
the first operand must either return 'true' or 'false'
or raise an exception;
the second operand, if executed, must either return
'true' or 'false' or raise an exception;
the Dialyzer will complain if either operand looks
as if it will return something other than 'false' or 'true';
and above all:
you CANNOT use them to get the same effect as
Lisp's (OR - -) and (AND - -) or Python's similar
operators, which allow a normal result from the
second operand to be anything at all.
I have in fact complained about this, not because I particularly
want non-Boolean results from these operators, but because the
code that's inserted to check makes them non-tail-recursive.
Indeed, the failure of these operators to be properly
tail-recursive makes them utterly useless, and dangerous.
The HiPE compiler once had a performance bug in its
register allocator because some code used an 'andalso'
to control a tail-recursive computation. Needless to say
I've since placed a ban on andalso/orelse in the HiPE code
I maintain.
David
> -----Original Message-----
> From: erlang-quest...@erlang.org [mailto:erlang-questions-
> bou...@erlang.org] On Behalf Of Mikael Pettersson
> Sent: Wednesday, November 19, 2008 03:09
> To: Richard O'Keefe
> Cc: erlang-q...@erlang.org
> Subject: Re: [erlang-questions] conditional expressions
>
It checks that the return value of the right hand side is a boolean,
so it must wait for the evaluation to return; it can't just do a tail
call if the left hand side evaluates to true. (The OTP folks thought
that error checking was more important than tail recursion for these
operators.)
/Richard
Maybe we should reconsider that decision for R13.
I agree with Mikael that andalso/orelse are both useless and dangerous.
/Bjorn
--
Björn Gustavsson, Erlang/OTP, Ericsson AB
Thanks for the reply, but I still do not understand. If the first operand
evaluates to true the second operand must necessarily be checked, since they
both have to be true in order for the expression to evaluate to true. What
am I missing (or mißing :-) )?
Cheers,
David
If the LHS is true, then it all hangs on the RHS, so you can A) call it
with a tail call (if the result of the andalso will be returned as the
result of the current function) and hope that it evaluates to a boolean
as it ought to, or B) call it, get the return value, check that it is
indeed a boolean, and either return it as it is or throw an exception
if it is not a boolean.
The current implementation does B, which makes it less suitable for
this kind of thing:
all_true([H|T]) -> H andalso all_true(T);
all_true([]) -> true.
which would be a simple traversal if the implementation was A,
but as it is, we have to return down the stack and check that we
are getting neat little booleans all the way. (Yes, type analysis
could sometimes save the day, but far from always.)
On the other hand, B prevents uses such as this:
maybe_goodbye(X) -> X andalso io:format("adieu").
(which returns false if X is false, and otherwise prints
a message and returns ok).
/Richard
> Can someone please explain the tail recursion problem with andalso?
SML:
fun all(f, []) = true
| all(f, x::xs) = f x andalso all(f, xs);
The recursive call here is a tail call:
when that recursive call is finished there is nothing
to be done with the result except to return it.
Erlang:
all(_, []) -> true;
all(F, [X|Xs]) -> F(X) andalso all(F, Xs).
The recursive call here is NOT a tail call,
because it is semantically the equivalent of
all(_, []) -> true;
all(F, [X|Xs]) ->
case F(X)
of false -> false
; true -> R = all(F, Xs),
if R == true ; R == false -> R end
end.
Of course SML and Haskell don't need to check because the
type system means that the code that gets past the compiler
couldn't possibly fail such a check. But Lisp and Smalltalk
and Python don't bother making any such check, even though
it _might_ fail if it _were_ done.
Skipping the check on R doesn't seem to be much of a problem
in practice. Loss of tail recursion here IS a problem.