Создание правильного объявления функции из сложной структуры кортежа / списка - PullRequest
1 голос
/ 14 июня 2011

Есть ли общий способ, учитывая сложный объект в Erlang, придумать для него допустимое объявление функции, помимо того, что его можно было бы увидеть? Я поддерживаю некоторый код, ранее написанный кем-то, кто был большим поклонником гигантских структур, и это оказывается склонным к ошибкам, делающим это вручную. Мне не нужно повторять все это, просто захватите верхний уровень как таковой.

Например, я сейчас работаю над этим -

[[["SIP",47,"2",46,"0"],32,"407",32,"Proxy Authentication Required","\r\n"],
 [{'Via',
        [{'via-parm',
              {'sent-protocol',"SIP","2.0","UDP"},
              {'sent-by',"172.20.10.5","5060"},
              [{'via-branch',"z9hG4bKb561e4f03a40c4439ba375b2ac3c9f91.0"}]}]},
  {'Via',
        [{'via-parm',
              {'sent-protocol',"SIP","2.0","UDP"},
              {'sent-by',"172.20.10.15","5060"},
              [{'via-branch',"12dee0b2f48309f40b7857b9c73be9ac"}]}]},
  {'From',
        {'from-spec',
             {'name-addr',
                  [[]],
                  {'SIP-URI',
                        [{userinfo,{user,"003018CFE4EF"},[]}],
                        {hostport,"172.20.10.11",[]},
                        {'uri-parameters',[]},
                        []}},
             [{tag,"b7226ffa86c46af7bf6e32969ad16940"}]}},
  {'To',
        {'name-addr',
             [[]],
             {'SIP-URI',
                  [{userinfo,{user,"3966"},[]}],
                  {hostport,"172.20.10.11",[]},
                  {'uri-parameters',[]},
                  []}},
        [{tag,"a830c764"}]},
  {'Call-ID',"90df0e4968c9a4545a009b1adf268605@172.20.10.15"},
  {'CSeq',1358286,"SUBSCRIBE"},
  ["date",'HCOLON',
    ["Mon",44,32,["13",32,"Jun",32,"2011"],32,["17",58,"03",58,"55"],32,"GMT"]],
  {'Contact',
        [[{'name-addr',
                [[]],
                {'SIP-URI',
                     [{userinfo,{user,"3ComCallProcessor"},[]}],
                     {hostport,"172.20.10.11",[]},
                     {'uri-parameters',[]},
                     []}},
          []],
         []]},
  ["expires",'HCOLON',3600],
  ["user-agent",'HCOLON',
    ["3Com",[]],
    [['LWS',["VCX",[]]],
     ['LWS',["7210",[]]],
     ['LWS',["IP",[]]],
     ['LWS',["CallProcessor",[['SLASH',"v10.0.8"]]]]]],
  ["proxy-authenticate",'HCOLON',
    ["Digest",'LWS',
     ["realm",'EQUAL',['SWS',34,"3Com",34]],
     [['COMMA',["domain",'EQUAL',['SWS',34,"3Com",34]]],
      ['COMMA',
        ["nonce",'EQUAL',
         ['SWS',34,"btbvbsbzbBbAbwbybvbxbCbtbzbubqbubsbqbtbsbqbtbxbCbxbsbybs",
          34]]],
      ['COMMA',["stale",'EQUAL',"FALSE"]],
      ['COMMA',["algorithm",'EQUAL',"MD5"]]]]],
  {'Content-Length',0}],
 "\r\n",
 ["\n"]]

Ответы [ 5 ]

3 голосов
/ 15 июня 2011

Может быть https://github.com/etrepum/kvc

1 голос
/ 15 июня 2011

Я заметил ваш уточняющий комментарий.Я бы предпочел добавить комментарий сам, но мне не хватает кармы.В любом случае, для этого я использую эксперимент с оболочкой.Я буду повторять шаблон по образцу структуры данных, пока не найду простейшую форму.Вы можете использовать переменную _ match-all.Я использую оболочку erlang внутри окна оболочки emacs.

Сначала свяжите образец с переменной:

A = [{a, b}, [{c, d}, {e, f}]].

Теперь установите исходную структуру для переменной:

[{a, b}, [{c, d},{e, f}]] = A.

Если вы нажмете Enter, вы увидите, что они совпадают.Нажмите alt-p (забудьте, что emacs называет alt, но это alt на моей клавиатуре), чтобы вернуть предыдущую строку.Замените некоторый кортеж или элемент списка подчеркиванием:

[_, [{c, d}, {e, f}]].

Нажмите Enter, чтобы сделатьуверен, что вы сделали это правильно, и они все еще совпадают.Этот пример тривиален, но для глубоко вложенных многострочных структур он сложнее, поэтому удобно иметь возможность просто быстро сопоставить его с тестом.Иногда вы можете попытаться угадать целые огромные полосы, например, использовать подчеркивание для сопоставления списка кортежей внутри кортежа, который является третьим элементом списка.Если вы поместите это правильно, вы можете сопоставить все это сразу, но это легко неправильно понять.

В любом случае, повторите, чтобы изучить основную форму структуры и разместить реальные переменные там, где вы хотите извлечь значения:

[_, [_, _]] = A.

[_, _] = A.

[_, MyTupleList] = A. %% давайте возьмем этот список кортежей

[{MyAtom, b}, [{c, d}, MyTuple]] = A. %% или, может быть, мы хотим, чтобы этот атом и кортеж

Вот как я эффективно анализирую и сопоставляю образцы сложных структур данных.

Однако,Я не знаю, что ты делаешь.Я был бы склонен иметь функцию-обертку, которая использует KVC для извлечения именно того, что вам нужно, а затем распределяет оттуда вспомогательные функции для каждого типа структуры.

1 голос
/ 15 июня 2011

Трудно что-то порекомендовать для обработки этого.

Преобразование всех структур в более вменяемый, а также в более минималистский формат выглядит оправданным.Это зависит главным образом от сходства в этих структурах.

Вместо того, чтобы иметь специальную функцию для каждого из 100, должно быть некоторое автоматическое переформатирование, которое может быть сделано, возможно даже помещать части в записи.

Когда у вас есть записи, гораздо проще написать для них функции, поскольку вам не нужно знать фактическое количество элементов в записи.Что еще более важно: ваш код не сломается при изменении количества элементов.

Подводя итог: создайте барьер между вашим кодом и безумием этих структур, каким-то образом санировав их с помощью самого общего из возможных кодов.Вероятно, это будет смесь общего переформатирования со специфическими для структуры вещами.

Как пример, уже видимый в этой структуре: кортежи 'name-addr' выглядят так, как будто они имеют однородную структуру.Таким образом, вы можете перебирать свои структуры (по всем элементам кортежей и списков) и сопоставлять «вещи», которые имеют общую структуру, такую ​​как 'name-addr', и заменять их хорошими записями.вы можете написать себе вспомогательные функции в этом примере:

eyeball(List) when is_list(List) ->
    io:format("List with length ~b\n", [length(List)]);
eyeball(Tuple) when is_tuple(Tuple) ->
    io:format("Tuple with ~b elements\n", [tuple_size(Tuple)]).

Таким образом, вы получите такой вывод:

2> eyeball({a,b,c}).
Tuple with 3 elements
ok
3> eyeball([a,b,c]).
List with length 3
ok

расширение этого полезного инструмента для вашего использования оставлено какупражнение.Вы можете обрабатывать несколько уровней, повторяя элементы и делая отступ.

1 голос
/ 15 июня 2011

Если я правильно вас понимаю, вы хотите, чтобы шаблон соответствовал некоторым крупным структурам данных неизвестного форматирования.

Пример:

Input: {a, b} {a,b,c,d} {a,[],{},{b,c}}

function({A, B}) -> do_something;
function({A, B, C, D}) when is_atom(B) -> do_something_else;
function({A, B, C, D}) when is_list(B) -> more_doing.

Общий ответ, конечно, состоит в том, что он не может быть решен только из данных.чтобы знать, как классифицировать эти данные.

Во-первых, вы должны знать о iolists.Они создаются такими функциями, как io_lib: format / 2 и во многих других местах кода.

Одним из примеров является то, что

 [["SIP",47,"2",46,"0"],32,"407",32,"Proxy Authentication Required","\r\n"]

будет печататься как

 SIP/2.0 407 Proxy Authentication Required

Итак, я бы начал со сглаживания всех этих списков, используя такую ​​функцию, как

 flatten_io(List) when is_list(List) ->
     Flat = lists:map(fun flatten_io/1, List),
     maybe_flatten(Flat);
 flatten_io(Tuple) when is_tuple(Tuple) ->
      list_to_tuple([flatten_io(Element) || Element <- tuple_to_list(Tuple)];
 flatten_io(Other) -> Other.

 maybe_flatten(L) when is_list(L) ->
      case lists:all(fun(Ch) when Ch > 0 andalso Ch < 256 -> true;
                   (List) when is_list(List) ->
                        lists:all(fun(X) -> X > 0 andalso X < 256 end, List);
                   (_) -> false
                end, L) of
          true -> lists:flatten(L);
          false -> L
      end.

(Предупреждение: полностью не проверено и совершенно неэффективно. Также произойдет сбой для неподходящих списков, но вы не должны иметьв любом случае, в ваших структурах данных.)

Если подумать, я не могу вам помочь.Любая структура данных, которая использует атом 'COMMA' для запятой в строке, должна быть извлечена и снята.

Вы также должны быть в состоянии сгладить эти вещи и начать получать представление о том, что вы ищетеat.

Я знаю, что это не полный ответ.Надеюсь, это поможет.

0 голосов
/ 15 июня 2011

Используйте сопоставление с образцом и функции, которые работают со списками, чтобы извлечь только то, что вам нужно.

Посмотрите на http://www.erlang.org/doc/man/lists.html: keyfind, keyreplace, L = [H|T], ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...