[erlang-questions] : lists:keyfind as an alternative to lists:keysearch

Raimo Niskanen raimo+erlang-questions@REDACTED
Thu Jan 22 09:22:24 CET 2009

On Wed, Jan 21, 2009 at 05:20:42PM +0100, Robert Virding wrote:
> 2009/1/21 Bjorn Gustavsson <bgustavsson@REDACTED>
> > On Wed, Jan 21, 2009 at 4:40 PM, mats cronqvist <masse@REDACTED> wrote:
> > > Bjorn Gustavsson <bgustavsson@REDACTED> writes:
> > >
> > >>>  seems i've written this function at least a thousand times;
> > >>>
> > >>> keyfind(Key,N,List) ->
> > >>>  {value,{Key,Val} = lists:keysearch(Key,N,List),
> > >>>  Val.
> > >>
> > >> This version only works for tuples of size 2.
> > >
> > >  it was meant as an example, not an implementation proposal. i didn't
> > >  balance the braces either :<
> >
> > Yes, but if the tuple has more than two elements, how do you know
> > which field the caller is interested in? Do you assume that it always
> > the element after the key? What is the caller is interested in several
> > fields of the tuple?
> I am sorry, but I think that returning something "half-tagged" like
> ValueTuple | false (/not_found/error/...) is horrendous and should be
> avoided like the plague. I think the Right Way is to tag both return values
> as is done with keyserach, but I agree that using {value,Val} | false is

In the everlasting battle between efficiency and beauty, I think
in this case the fact that anything found will have to be a tuple
should be exploited for the sake of efficiency.

That is; I vote for keyfind/3 -> Tuple | false. Otherwise the demand
for a more efficient keyfind/3 function will eventually come. Anyone
willing to sacrifice efficienty can write their own wrapper. The other
way around is not possible.

For a general lookup function i think the suggested arity 4
function is very handy. If you are able to choose your 
"not found" value, you can always use a ref() and thus
build both a "crash when not found" function, or a
"always tagged return value".

But for an efficient general lookup API there should
exist a "crash when not found" function _and_ a
"always tagged return value" function.

For lists:keyfind/3 or any *:*key* function
this is not necessary.

> bad. If we are going to "fix" it then I would suggest two functions like in
> dict, find/2 to find a value if it exists and one which assumes it exists
> and errors otherwise. I also agree that returning 'error' is not the best as
> it may very well not be an error, with 20/20 hindsight I would prefer a
> maybe(value) so:
> keyfind(Key, N, List) -> {yes,Value} | no.
> keyfetch(Key, N, List) -> Value (or exception)
> If you want to be more consistent with existing modules like dict then use
> {ok,Value} | error instead.
> Just because lisp has a convention of returning value or nil, this is not
> something we should really copy as they also have the convention that (car
> ()) => () and (cdr ()) => () which are used together with functions
> returning nil for not found. In erlang terms that would mean hd([]) => [],
> tl([]) => [] and [] matches [[]].
> Now this would help make LFE more lisp-like but I don't advocate it.
> If you are going to tag return values then you must tag them all, otherwise
> you will be bitten. And the extra cost *is* neglible.
> Robert

> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://www.erlang.org/mailman/listinfo/erlang-questions


/ Raimo Niskanen, Erlang/OTP, Ericsson AB

More information about the erlang-questions mailing list