Erlang/OTP Forums

Author Message

<  Erlang  ~  Matching question

autophile
Posted: Mon Dec 03, 2007 1:59 am Reply with quote
User Joined: 12 Jan 2007 Posts: 31 Location: Maryland, USA
Hi all,

Is there any way to do something like this:

Code:

% Input = string()
% Prefix = string()

Prefix = generate_complicated_prefix(),
case Input of
  [ Prefix | Tail ] ->
    do_something(Tail);
  [ $X, Prefix | Tail ] ->
    do_something_else(Tail)
end.


Obviously this won't work, because the case clauses turn out to be deep lists -- I need a flattened list to match against. Any ideas as to the Erlangy way to do this? I'm kind of dreading that the answer will turn out to require lists module calls Sad

Thanks,

--Rob
View user's profile Send private message
michal
Posted: Mon Dec 03, 2007 12:39 pm Reply with quote
User Joined: 20 Jul 2006 Posts: 44 Location: London
If all your lists are short, you can rewrite your case statement as:

Code:

case Input of
  Prefix ++ Tail ->
    do_something(Tail);
  [$X|Prefix] ++ Tail ->
    do_something_else(Tail)
end.


However ++ operator is quite expensive and if Tail or Prefix are long lists it will impact the performance.

Michal

_________________
http://www.erlang-consulting.com
View user's profile Send private message
autophile
Posted: Mon Dec 03, 2007 1:55 pm Reply with quote
User Joined: 12 Jan 2007 Posts: 31 Location: Maryland, USA
According to the erl shell, Prefix ++ Tail is an illegal pattern. I guess all variables in a ++ expression have to be bound, and Tail is not bound.

Any other ideas?
View user's profile Send private message
Adam
Posted: Tue Dec 11, 2007 2:34 pm Reply with quote
User Joined: 23 Aug 2006 Posts: 71 Location: London
In a function header you can write:

Code:
func("test" ++ Rest) ->
    Rest.


Which in the case of the input "teststring" will bind Rest to "string". Should be the same for any pattern matching.

_________________
Adam
Erlang Training & Consulting
View user's profile Send private message Visit poster's website MSN Messenger ICQ Number
autophile
Posted: Tue Dec 11, 2007 8:32 pm Reply with quote
User Joined: 12 Jan 2007 Posts: 31 Location: Maryland, USA
Well, I'm not matching against a fixed string. I'm matching against a variable.
View user's profile Send private message
bluefly
Posted: Mon Jan 07, 2008 12:08 am Reply with quote
User Joined: 06 Jan 2008 Posts: 10
I am an Erlang newbie, but I feel I have a fair handle on the language in general. Here would be my approach to your problem. I am assuming that you want to match a sublist in a list (or a substring in a string).

There is no way to match a sublist in a list in a guard expression. For one, there is no syntax for it (the syntax is limited to things like the head vs tail of the list). For another, there is no BIF (akin to is_list(), is_integer()) or operator that does this; this means you cannot do this matching in a guard expression either. These two issues knock out unique function header matching and use of "when".

Remember that guards are not allowed to have potential side effects, so they are extra limited.

However, we can still store the results of a match in a variable and then make simple comparisons against the variable.

Here is some tested code that demonstrates the concept, including it crashing when we reach an unexpected prefix situation:

Code:
-module(junk).
-export([start/0]).

start() ->
    Prefix = generate_complicated_prefix(),

    Input = Prefix ++ "this is the tail",
    io:format("Input with prefix: ~s~n", [Input]),
    process_input(Prefix, Input),

    XInput = [$X | Input],
    io:format("Input with complicated prefix: ~s~n", [XInput]),
    process_input(Prefix, XInput),

    BadInput = [$B | Input],
    io:format("Bad input: ~s~n", [BadInput]),
    process_input(Prefix, BadInput).

generate_complicated_prefix() ->
    "some complicated prefix 123_yeah".

process_input(Prefix, Input) ->
    {Prefix_Type, Tail} = get_tail(Prefix, Input),
    case Prefix_Type of
        simple -> do_something(Tail);
        complicated -> do_something_else(Tail)
    end.

get_tail(Prefix, Input) ->
    Is_Simple_Prefix = string:equal(
        string:substr(Input, 1, length(Prefix)),
        Prefix
    ),
    Is_Complicated_Prefix = string:equal(
        string:substr(Input, 1, length(Prefix) + 1),
        [$X | Prefix]
    ),

    if
        Is_Simple_Prefix -> get_tail(Prefix, Input, simple);
        Is_Complicated_Prefix -> get_tail(Prefix, Input, complicated)
    end.

get_tail(Prefix, Input, simple) ->
    {simple, string:substr(Input, length(Prefix) + 1)};

get_tail(Prefix, Input, complicated) ->
    {complicated, string:substr(Input, length(Prefix) + 2)}.

do_something(Tail) ->
    io:format("do_something(~s)~n", [Tail]).

do_something_else(Tail) ->
    io:format("do_something_else(~s)~n", [Tail]).


I tried to make this elegant, but I welcome comments on how to improve this.
View user's profile Send private message

Display posts from previous:  

All times are GMT
Page 1 of 1
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum