<div dir="ltr"><br>Hi Joe,<div><br></div><div>I recently investigated this topic and found the following rebar3 plugin you can use (if you are using rebar3) - <a href="https://github.com/barrel-db/rebar3_elixir_compile">https://github.com/barrel-db/rebar3_elixir_compile</a>. I think it supports both your own Elixir code and Elixir dependencies, it automatically builds all of those so you can use them from your Erlang code. And using it from Erlang shouldn't be a problem once you know some Elixir basics (at least how the types are mapped between Ex and Erl). There's one plugin for old rebar too I believe.</div><div><br></div><div>While I tried the above plugin and it seemed to work fine (on a smallish project) I found that using mix (Elixir's build tool) worked much better. Since mix supports both Erlang and Elixir out-of-the-box it seemed more natural for mixed projects (again tested only on a smallish test project, more info can be found at <a href="https://hexdocs.pm/mix/Mix.Tasks.Compile.Erlang.html#content">https://hexdocs.pm/mix/Mix.Tasks.Compile.Erlang.html#content</a>).</div><div><br></div><div>Regards,</div><div>Jonas Trantina</div><div><br></div><div><div class="gmail_quote"><div dir="ltr">út 8. 8. 2017 v 10:01 odesílatel Joe Armstrong <<a href="mailto:erlang@gmail.com">erlang@gmail.com</a>> napsal:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello,<br>
<br>
I'm going to go way off topic here and not answer your specific<br>
question about lists ...<br>
<br>
Your last mail had the information I need - you're trying to parse HL7.<br>
I have a few comments.<br>
<br>
1) Your original question did not bother to mention  what problem you<br>
were trying to solve -<br>
    You asked about a sub-problem that you encountered when trying to<br>
solve your principle<br>
    problem (principle problem = parse HL7) (sub-problem = differentiate lists)<br>
<br>
 2) It's *always* a good idea to ask questions about the principle<br>
problem first !!!!<br>
<br>
I didn't know what HL7 was - my immediate thought was<br>
 'I wonder if anybody has written an *proper* HL7 parser in Erlang' - by<br>
proper I mean "has expended a significant amount of thought on writing a parser"<br>
<br>
Google is your friend - It told me what HL7 was (I hadn't a clue here<br>
- "never heard of it")<br>
and it turned up a parser in elixir<br>
<br>
    <a href="https://github.com/jcomellas/ex_hl7" rel="noreferrer" target="_blank">https://github.com/jcomellas/ex_hl7</a><br>
<br>
>From the quality of the documentation I assume this is a *proper*<br>
implementation.<br>
<br>
Now elixir compiles to .beam files and can be called from Erlang -<br>
which raises another<br>
sub problem "how do I compile the elixir code and call it from Erlang"<br>
and begs the<br>
question "is this effort worthwhile"<br>
<br>
Given that a parser for HL7 exists in elixir it might be sensible to<br>
use it "off the shelf"<br>
<br>
I have a feeling that elixir folks are good at reusing erlang code -<br>
but that reuse in the<br>
opposite direction is less easy.<br>
<br>
The last time I fiddled a bit (yesterday as it happened) - it turned<br>
out to be less than<br>
blindingly obvious how to call other than trivial elixir code from erlang.<br>
<br>
I was also wondering about cross-compilation. Has anybody written<br>
something that turns<br>
erlang code into elixir source code or vice. versa.<br>
<br>
Cheers<br>
<br>
/Joe<br>
<br>
<br>
<br>
<br>
<br>
On Mon, Aug 7, 2017 at 3:46 PM, Andrew McIntyre<br>
<<a href="mailto:andrew@medical-objects.com.au" target="_blank">andrew@medical-objects.com.au</a>> wrote:<br>
> Hello Craig,<br>
><br>
> Thanks for your help.<br>
><br>
> I am trying to store the data as efficiently as possible. Its HL7<br>
> natively and this is my test:<br>
><br>
> OBX|17|FT~TEST|8265-1^^LN&SUBCOMP|1&2&3&4|\H\Spot Image 2\N\||||||F<br>
><br>
> |~^& are delimiters. The hierarchy is only so deep and using lists of<br>
> lists to provide a tree like way to access the data eg Field 3, repeat<br>
> 1 component 2 subcomponent1<br>
><br>
> Parsed it looks like this:<br>
><br>
> [["OBX","17",<br>
>   ["FT","TEST"],<br>
>   [["8265-1",[],["LN","SUBCOMP"]]],<br>
>   [[["1","2","3","4"]]],<br>
>   "\\H\\Spot Image 2\\N\\",[],[],[],[],[],"F"]]<br>
><br>
> As the format evolves over time the hierarchy can be extended, but<br>
> older clients can still read the value they are expecting if they<br>
> follow the rules, like reading the first value in the list when you<br>
> only expect one value to be there.<br>
><br>
> Currently a typical system might have 12 million of these records so<br>
> want to keep format as small as possible in the erlang format, hence<br>
> reluctant to tag 2 much, but know how to get value of interest. Maybe<br>
> that is my non erlang background showing up? Traversing 4 small lists<br>
> by index should be fast??<br>
><br>
> I guess I could save strings as binary in the lists then is_binary<br>
> should work?? Is that the case. I gather on 64bit system especially<br>
> binary is more space efficient.<br>
><br>
> Monday, August 7, 2017, 10:53:11 PM, you wrote:<br>
><br>
> z> On 2017年08月07日 月曜日 22:29:31 you wrote:<br>
>>> Hello zxq9,<br>
>>><br>
>>> Thanks, Unfortunately I do not know the value of the string that will<br>
>>> be there. Its an extensible hierarchy that can be several lists deep -<br>
>>> or not. Might need to revise the data structure<br>
><br>
> z> In this case it can be useful to consider a way of tagging values.<br>
><br>
> z> Imagine we want to represent a directory tree structure and have a<br>
> z> descent-first traversal function recurse over it while creating the<br>
> z> tree. We have two things that can happen, there is a flat list of<br>
> z> new directories that need to be created, and there is the<br>
> z> possibility that the tree depth extends deeper at each node.<br>
><br>
> z> The naive version would look like what you have:<br>
><br>
> z> ["top_dir_1",<br>
> z>  "top_dir_2",<br>
> z>  ["next_level_1",<br>
> z>   "next_level_2"]]<br>
><br>
> z> This leaves a bit to be desired, not only because of the problem<br>
> z> you have pointed out that makes it difficult to know what is deep<br>
> z> and what is shallow, but also because we don't really have a good<br>
> z> way to represent a full tree (what would be the name of a directory containing other directories?).<br>
><br>
> z> So consider instead something like this:<br>
><br>
> z> [{"top_dir_1", []},<br>
> z>  {"top_dir_2", []},<br>
> z>  {"top_dir_3",<br>
> z>   [{"next_level_1", []},<br>
> z>    {"next_level_2", []}]}]<br>
><br>
> z> Now we have a representation of each directory's name AND its contents.<br>
><br>
> z> We can traverse this laterally AND in depth without any ambiguity<br>
> z> or need for carrying around a record of where we have been (by<br>
> z> using depth recursion and tail-call recursion):<br>
><br>
><br>
> z> make_tree([{Dir, Contents} | Rest]) -><br>
> z>     ok =<br>
> z>         case filelib:is_dir(Dir) of<br>
> z>             true -><br>
> z>                 ok;<br>
> z>             false -><br>
> z>                 ok = log(info, "Creating dir: ~p", [Dir]),<br>
> z>                 file:make_dir(Dir)<br>
> z>         end,<br>
> z>     ok = file:set_cwd(Dir),<br>
> z>     ok = make_tree(Contents),<br>
> z>     ok = file:set_cwd(".."),<br>
> z>     make_tree(Rest);<br>
> make_tree([]) ->><br>
> z>     ok.<br>
><br>
><br>
> z> Not so bad.<br>
><br>
> z> In your case we could represent things perhaps a bit better by<br>
> z> separating the types and tagging them. Instead of just "FT" and<br>
> z> whatever other string labels you might want, you could either use<br>
> z> atoms (totally unambiguous) or tuples as we have in the example<br>
> z> able (also totally unambiguous). I prefer tuples, though, because they are easier to read.<br>
><br>
> z> [{value, "foo"},<br>
> z>  {tree,<br>
> z>   [{value, "bar"},<br>
> z>    {value, "foo"}]},<br>
> z>  {value, "baz"}]<br>
><br>
><br>
> z> So then we do something like:<br>
><br>
><br>
> z> traverse([{value, Value} | Rest]) -><br>
> z>    ok = do_thing(Value),<br>
> z>    traverse(Rest);<br>
> z> traverse([{tree, Contents} | Rest]) -><br>
> z>    ok = traverse(Contents),<br>
> z>    traverse(Rest);<br>
> traverse([]) ->><br>
> z>    ok.<br>
><br>
><br>
> z> Anyway, don't be afraid of varying your value types to say exactly<br>
> z> what you mean. If your strings like "FT" only had meaning within<br>
> z> your system consider NOT USING STRINGS, and using atoms instead. That makes it even easier:<br>
><br>
><br>
> z> [foo,<br>
> z>  bar,<br>
> z>  [foo,<br>
> z>   bar],<br>
> z>  foo]<br>
><br>
><br>
> z> So then we can do:<br>
><br>
><br>
> z> traverse([foo | Rest]) -><br>
> z>     ok = do_foo(),<br>
> z>     traverse(Rest);<br>
> z> traverse([bar | Rest]) -><br>
> z>     ok = do_bar(),<br>
> z>     traverse(Rest);<br>
> z> traverse([Value | Rest]) when is_list(Value) -><br>
> z>     ok = traverse(Value),<br>
> z>     traverse(Rest);<br>
> traverse([]) ->><br>
> z>     ok.<br>
><br>
><br>
> z> And of course, you can not use a guard if you want to match on a<br>
> z> list shape in the listy clause there, but that is a minor detail.<br>
> z> The point is to make your data types MEAN SOMETHING REASONABLE<br>
> z> within your system. Use atoms when your values are meaningful only<br>
> z> within your system. Strings are for the birds.<br>
><br>
> z> -Craig<br>
> z> _______________________________________________<br>
> z> erlang-questions mailing list<br>
> z> <a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
> z> <a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
><br>
><br>
><br>
> --<br>
> Best regards,<br>
>  Andrew                             mailto:<a href="mailto:andrew@Medical-Objects.com.au" target="_blank">andrew@Medical-Objects.com.au</a><br>
><br>
> sent from a real computer<br>
><br>
><br>
> _______________________________________________<br>
> erlang-questions mailing list<br>
> <a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
> <a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div></div></div>